From 8f5dc8900988f765f8a2ba60a3870be2a77e2a7f Mon Sep 17 00:00:00 2001 From: Leo6Leo <36619969+Leo6Leo@users.noreply.github.com> Date: Fri, 24 Oct 2025 10:24:23 -0400 Subject: [PATCH 01/16] feat: Refactor Knative plugin: replace plugin.tsx with plugin.ts, update console-extensions.json to include new topology data model factories for serving, eventing, and kamelets, and remove deprecated topology-plugin.ts file --- .../knative-plugin/console-extensions.json | 66 ++++++++++++++ frontend/packages/knative-plugin/package.json | 6 +- .../packages/knative-plugin/src/plugin.ts | 2 + .../packages/knative-plugin/src/plugin.tsx | 3 - .../src/topology/topology-plugin.ts | 91 ------------------- 5 files changed, 72 insertions(+), 96 deletions(-) create mode 100644 frontend/packages/knative-plugin/src/plugin.ts delete mode 100644 frontend/packages/knative-plugin/src/plugin.tsx delete mode 100644 frontend/packages/knative-plugin/src/topology/topology-plugin.ts diff --git a/frontend/packages/knative-plugin/console-extensions.json b/frontend/packages/knative-plugin/console-extensions.json index f50077e223f..88d47aa9f61 100644 --- a/frontend/packages/knative-plugin/console-extensions.json +++ b/frontend/packages/knative-plugin/console-extensions.json @@ -2008,5 +2008,71 @@ "flags": { "required": ["KNATIVE_EVENTING"] } + }, + { + "type": "console.topology/data/factory", + "properties": { + "id": "knative-serving-topology-model-factory", + "priority": 100, + "resources": { + "$codeRef": "getKnativeResources.getKnativeServingResources" + }, + "workloadKeys": ["ksservices"], + "getDataModel": { + "$codeRef": "dataTransformer.getKnativeServingTopologyDataModel" + }, + "isResourceDepicted": { + "$codeRef": "isKnativeResource.isKnativeResource" + } + }, + "flags": { + "required": [ + "KNATIVE_SERVING_CONFIGURATION", + "KNATIVE_SERVING", + "KNATIVE_SERVING_REVISION", + "KNATIVE_SERVING_ROUTE", + "KNATIVE_SERVING_SERVICE" + ] + } + }, + { + "type": "console.topology/data/factory", + "properties": { + "id": "knative-eventing-topology-model-factory", + "priority": 100, + "resources": { + "$codeRef": "getKnativeResources.getKnativeEventingResources" + }, + "workloadKeys": ["eventingsubscription"], + "getDataModel": { + "$codeRef": "dataTransformer.getKnativeEventingTopologyDataModel" + }, + "isResourceDepicted": { + "$codeRef": "isKnativeResource.isKnativeResource" + } + }, + "flags": { + "required": ["KNATIVE_EVENTING", "FLAG_KNATIVE_EVENTING_ENABLED"] + } + }, + { + "type": "console.topology/data/factory", + "properties": { + "id": "knative-kamelets-topology-model-factory", + "priority": 100, + "resources": { + "$codeRef": "getKnativeResources.getKnativeEventingKameletsResources" + }, + "workloadKeys": ["kameletbindings"], + "getDataModel": { + "$codeRef": "dataTransformer.getKnativeKameletsTopologyDataModel" + }, + "isResourceDepicted": { + "$codeRef": "isKnativeResource.isKnativeResource" + } + }, + "flags": { + "required": ["KNATIVE_EVENTING", "FLAG_CAMEL_KAMELETS"] + } } ] diff --git a/frontend/packages/knative-plugin/package.json b/frontend/packages/knative-plugin/package.json index 03ddc3edbec..3efe003e95a 100644 --- a/frontend/packages/knative-plugin/package.json +++ b/frontend/packages/knative-plugin/package.json @@ -14,7 +14,7 @@ "@console/topology": "0.0.0-fixed" }, "consolePlugin": { - "entry": "src/plugin.tsx", + "entry": "src/plugin.ts", "exposedModules": { "actions": "src/actions/providers.ts", "icons": "src/utils/icons.tsx", @@ -65,7 +65,9 @@ "fetchDynamicEventSourcesUtils": "src/utils/fetch-dynamic-eventsources-utils.ts", "EventSourceBreadcrumbs": "src/providers/useEventSourceDetailPageBreadcrumbs.ts", "ChannelBreadcrumbs": "src/providers/useChannelDetailPageBreadcrumbs.ts", - "BrokerBreadcrumbs": "src/providers/useBrokerDetailPageBreadcrumbs.ts" + "BrokerBreadcrumbs": "src/providers/useBrokerDetailPageBreadcrumbs.ts", + "getKnativeResources": "src/utils/get-knative-resources.ts", + "isKnativeResource": "src/topology/isKnativeResource.ts" } } } diff --git a/frontend/packages/knative-plugin/src/plugin.ts b/frontend/packages/knative-plugin/src/plugin.ts new file mode 100644 index 00000000000..ef8d3ac4f8a --- /dev/null +++ b/frontend/packages/knative-plugin/src/plugin.ts @@ -0,0 +1,2 @@ +// See console-extensions.json instead +export default []; diff --git a/frontend/packages/knative-plugin/src/plugin.tsx b/frontend/packages/knative-plugin/src/plugin.tsx deleted file mode 100644 index 0967881f109..00000000000 --- a/frontend/packages/knative-plugin/src/plugin.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { topologyPlugin } from './topology/topology-plugin'; - -export default topologyPlugin; diff --git a/frontend/packages/knative-plugin/src/topology/topology-plugin.ts b/frontend/packages/knative-plugin/src/topology/topology-plugin.ts deleted file mode 100644 index 9cfe6fe4be2..00000000000 --- a/frontend/packages/knative-plugin/src/topology/topology-plugin.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { applyCodeRefSymbol } from '@console/dynamic-plugin-sdk/src/coderefs/coderef-resolver'; -import { Plugin } from '@console/plugin-sdk'; -import { TopologyDataModelFactory } from '@console/topology/src/extensions'; -import { - FLAG_CAMEL_KAMELETS, - FLAG_KNATIVE_EVENTING, - FLAG_KNATIVE_EVENTING_ENABLED, - FLAG_KNATIVE_SERVING, - FLAG_KNATIVE_SERVING_CONFIGURATION, - FLAG_KNATIVE_SERVING_REVISION, - FLAG_KNATIVE_SERVING_ROUTE, - FLAG_KNATIVE_SERVING_SERVICE, -} from '../const'; -import { - getKnativeEventingKameletsResources, - getKnativeEventingResources, - getKnativeServingResources, -} from '../utils/get-knative-resources'; - -const getKnativeServingTopologyDataModel = () => - import('./data-transformer' /* webpackChunkName: "serving-components" */).then( - (m) => m.getKnativeServingTopologyDataModel, - ); - -const getKnativeEventingTopologyDataModel = () => - import('./data-transformer' /* webpackChunkName: "eventing-components" */).then( - (m) => m.getKnativeEventingTopologyDataModel, - ); - -const getKnativeKameletsTopologyDataModel = () => - import('./data-transformer' /* webpackChunkName: "kamelets-components" */).then( - (m) => m.getKnativeKameletsTopologyDataModel, - ); - -const getIsKnativeResource = () => - import('./isKnativeResource' /* webpackChunkName: "knative-components" */).then( - (m) => m.isKnativeResource, - ); - -export type TopologyConsumedExtensions = TopologyDataModelFactory; - -export const topologyPlugin: Plugin = [ - { - type: 'Topology/DataModelFactory', - properties: { - id: 'knative-serving-topology-model-factory', - priority: 100, - resources: getKnativeServingResources, - workloadKeys: ['ksservices'], - getDataModel: applyCodeRefSymbol(getKnativeServingTopologyDataModel), - isResourceDepicted: applyCodeRefSymbol(getIsKnativeResource), - }, - flags: { - required: [ - FLAG_KNATIVE_SERVING_CONFIGURATION, - FLAG_KNATIVE_SERVING, - FLAG_KNATIVE_SERVING_REVISION, - FLAG_KNATIVE_SERVING_ROUTE, - FLAG_KNATIVE_SERVING_SERVICE, - ], - }, - }, - { - type: 'Topology/DataModelFactory', - properties: { - id: 'knative-eventing-topology-model-factory', - priority: 100, - resources: getKnativeEventingResources, - workloadKeys: ['eventingsubscription'], - getDataModel: applyCodeRefSymbol(getKnativeEventingTopologyDataModel), - isResourceDepicted: applyCodeRefSymbol(getIsKnativeResource), - }, - flags: { - required: [FLAG_KNATIVE_EVENTING, FLAG_KNATIVE_EVENTING_ENABLED], - }, - }, - { - type: 'Topology/DataModelFactory', - properties: { - id: 'knative-kamelets-topology-model-factory', - priority: 100, - resources: getKnativeEventingKameletsResources, - workloadKeys: ['kameletbindings'], - getDataModel: applyCodeRefSymbol(getKnativeKameletsTopologyDataModel), - isResourceDepicted: applyCodeRefSymbol(getIsKnativeResource), - }, - flags: { - required: [FLAG_KNATIVE_EVENTING, FLAG_CAMEL_KAMELETS], - }, - }, -]; From 18fba1366b5a6a47b6c86d0e5a50bcb18d947d56 Mon Sep 17 00:00:00 2001 From: Leo6Leo <36619969+Leo6Leo@users.noreply.github.com> Date: Tue, 28 Oct 2025 14:26:23 -0400 Subject: [PATCH 02/16] CONSOLE-4806: Support CodeRef for topology resources property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable dynamic plugin extensions to use CodeRef for the resources property in topology data model factories. This allows plugins to fetch resources dynamically at runtime (e.g., discovering CRDs). Changes: - Update TopologyDataModelFactory type to accept CodeRef<() => Promise> - Add Promise resolution in DataModelExtension for CodeRef resources - Update get-knative-resources functions to return Promises with resource definitions - Maintain backward compatibility with static resource definitions The implementation follows the same pattern as other CodeRef properties (getDataModel, isResourceDepicted) by resolving the Promise eagerly during extension initialization and caching the result. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../docs/console-extensions.md | 2 +- .../src/extensions/topology.ts | 2 +- .../src/utils/get-knative-resources.ts | 107 +++++++++++++----- .../data-transforms/DataModelExtension.tsx | 85 ++++++++++++-- .../src/data-transforms/DataModelProvider.tsx | 19 +++- .../src/data-transforms/ModelContext.ts | 4 +- .../src/hooks/useTopologyDataModelFactory.ts | 101 +++++++++++++++++ 7 files changed, 279 insertions(+), 41 deletions(-) create mode 100644 frontend/packages/topology/src/hooks/useTopologyDataModelFactory.ts diff --git a/frontend/packages/console-dynamic-plugin-sdk/docs/console-extensions.md b/frontend/packages/console-dynamic-plugin-sdk/docs/console-extensions.md index 6763cca0492..6c26bbdeaba 100644 --- a/frontend/packages/console-dynamic-plugin-sdk/docs/console-extensions.md +++ b/frontend/packages/console-dynamic-plugin-sdk/docs/console-extensions.md @@ -1158,7 +1158,7 @@ Topology Data Model Factory Extension | ---- | ---------- | -------- | ----------- | | `id` | `string` | no | Unique ID for the factory. | | `priority` | `number` | no | Priority for the factory | -| `resources` | `WatchK8sResourcesGeneric` | yes | Resources to be fetched from useK8sWatchResources hook. | +| `resources` | `WatchK8sResourcesGeneric \| CodeRef<() => Promise>` | yes | Resources to be fetched from useK8sWatchResources hook. | | `workloadKeys` | `string[]` | yes | Keys in resources containing workloads. | | `getDataModel` | `CodeRef` | yes | Getter for the data model factory | | `isResourceDepicted` | `CodeRef` | yes | Getter for function to determine if a resource is depicted by this model factory | diff --git a/frontend/packages/console-dynamic-plugin-sdk/src/extensions/topology.ts b/frontend/packages/console-dynamic-plugin-sdk/src/extensions/topology.ts index b395c5e0737..f930df6937b 100644 --- a/frontend/packages/console-dynamic-plugin-sdk/src/extensions/topology.ts +++ b/frontend/packages/console-dynamic-plugin-sdk/src/extensions/topology.ts @@ -41,7 +41,7 @@ export type TopologyDataModelFactory = ExtensionDeclaration< /** Priority for the factory */ priority: number; /** Resources to be fetched from useK8sWatchResources hook. */ - resources?: WatchK8sResourcesGeneric; + resources?: WatchK8sResourcesGeneric | CodeRef<() => Promise>; /** Keys in resources containing workloads. */ workloadKeys?: string[]; /** Getter for the data model factory */ diff --git a/frontend/packages/knative-plugin/src/utils/get-knative-resources.ts b/frontend/packages/knative-plugin/src/utils/get-knative-resources.ts index f906d105139..9bfcb685165 100644 --- a/frontend/packages/knative-plugin/src/utils/get-knative-resources.ts +++ b/frontend/packages/knative-plugin/src/utils/get-knative-resources.ts @@ -21,10 +21,7 @@ import { KafkaConnectionModel, } from '../models'; import { Traffic } from '../types'; -import { - getDynamicEventSourcesWatchers, - getDynamicEventingChannelWatchers, -} from './fetch-dynamic-eventsources-utils'; +import { fetchEventSourcesCrd, fetchChannelsCrd } from './fetch-dynamic-eventsources-utils'; export type KnativeItem = { revisions?: K8sResourceKind[]; @@ -438,31 +435,87 @@ export const getSinkableResources = (namespace: string): FirehoseResource[] => { : []; }; -export const getKnativeServingResources = (namespace: string) => { - return { - ...knativeServingResourcesRevisionWatchers(namespace), - ...knativeServingResourcesConfigurationsWatchers(namespace), - ...knativeServingResourcesRoutesWatchers(namespace), - ...knativeServingResourcesServicesWatchers(namespace), - ...knativeCamelDomainMappingResourceWatchers(namespace), - }; -}; +export const getKnativeServingResources = () => + Promise.resolve({ + revisions: { + model: { group: 'serving.knative.dev', version: 'v1', kind: 'Revision' }, + opts: { isList: true, optional: true, namespaced: true }, + }, + configurations: { + model: { group: 'serving.knative.dev', version: 'v1', kind: 'Configuration' }, + opts: { isList: true, optional: true, namespaced: true }, + }, + ksroutes: { + model: { group: 'serving.knative.dev', version: 'v1', kind: 'Route' }, + opts: { isList: true, optional: true, namespaced: true }, + }, + ksservices: { + model: { group: 'serving.knative.dev', version: 'v1', kind: 'Service' }, + opts: { isList: true, optional: true, namespaced: true }, + }, + domainmappings: { + model: { group: 'serving.knative.dev', version: 'v1beta1', kind: 'DomainMapping' }, + opts: { isList: true, optional: true, namespaced: true }, + }, + }); + +export const getKnativeEventingResources = async () => { + // Fetch dynamic event sources and channels at runtime + const eventSourceModels = await fetchEventSourcesCrd(); + const eventingChannels = await fetchChannelsCrd(); + + const dynamicEventSources = eventSourceModels.reduce((acc, model) => { + const ref = referenceForModel(model); + acc[ref] = { + model: { group: model.apiGroup, version: model.apiVersion, kind: model.kind }, + opts: { isList: true, optional: true, namespaced: true }, + }; + return acc; + }, {}); + + const dynamicChannels = eventingChannels.reduce((acc, model) => { + const ref = referenceForModel(model); + acc[ref] = { + model: { group: model.apiGroup, version: model.apiVersion, kind: model.kind }, + opts: { isList: true, optional: true, namespaced: true }, + }; + return acc; + }, {}); -export const getKnativeEventingResources = (namespace: string) => { return { - ...knativeEventingResourcesSubscriptionWatchers(namespace), - ...getDynamicEventSourcesWatchers(namespace), - ...getDynamicEventingChannelWatchers(namespace), - ...knativeEventingBrokerResourceWatchers(namespace), - ...knativeEventingTriggerResourceWatchers(namespace), + eventingsubscription: { + model: { group: 'messaging.knative.dev', version: 'v1', kind: 'Subscription' }, + opts: { isList: true, optional: true, namespaced: true }, + }, + brokers: { + model: { group: 'eventing.knative.dev', version: 'v1', kind: 'Broker' }, + opts: { isList: true, optional: true, namespaced: true }, + }, + triggers: { + model: { group: 'eventing.knative.dev', version: 'v1', kind: 'Trigger' }, + opts: { isList: true, optional: true, namespaced: true }, + }, + ...dynamicEventSources, + ...dynamicChannels, }; }; -export const getKnativeEventingKameletsResources = (namespace: string) => { - return { - ...knativeCamelIntegrationsResourceWatchers(namespace), - ...knativeCamelKameletBindingResourceWatchers(namespace), - ...knativeCamelDomainMappingResourceWatchers(namespace), - ...knativeCamelKameletResourceWatchers(namespace), - }; -}; +export const getKnativeEventingKameletsResources = () => + Promise.resolve({ + integrations: { + model: { group: 'camel.apache.org', version: 'v1', kind: 'Integration' }, + opts: { isList: true, optional: true, namespaced: true }, + }, + kameletbindings: { + model: { group: 'camel.apache.org', version: 'v1alpha1', kind: 'KameletBinding' }, + opts: { isList: true, optional: true, namespaced: true }, + }, + domainmappings: { + model: { group: 'serving.knative.dev', version: 'v1beta1', kind: 'DomainMapping' }, + opts: { isList: true, optional: true, namespaced: true }, + }, + kamelets: { + model: { group: 'camel.apache.org', version: 'v1alpha1', kind: 'Kamelet' }, + opts: { isList: true, optional: true, namespaced: true }, + }, + }); diff --git a/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx b/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx index 0e2e4c7df65..38890a76aca 100644 --- a/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx +++ b/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx @@ -1,29 +1,98 @@ -import * as React from 'react'; +import { useContext, useRef, useEffect, useMemo } from 'react'; +import { + WatchK8sResources, + WatchK8sResourcesGeneric, + WatchK8sResource, +} from '@console/dynamic-plugin-sdk'; +import { referenceForModel, modelForGroupKind } from '@console/internal/module/k8s'; import { useDeepCompareMemoize } from '@console/shared'; import { TopologyDataModelFactory } from '../extensions/topology'; +import { useResolvedResources } from '../hooks/useTopologyDataModelFactory'; import { ModelContext, ExtensibleModel, ModelExtensionContext } from './ModelContext'; interface DataModelExtensionProps { dataModelFactory: TopologyDataModelFactory['properties']; } +/** + * Converts a single resource from WatchK8sResourcesGeneric format to WatchK8sResource format. + * This handles the namespace injection and model reference resolution. + */ +const convertGenericResource = ( + namespace: string, + model?: { group?: string; version?: string; kind: string }, + opts?: Partial, +): WatchK8sResource | null => { + if (!model) { + return { namespace, ...opts }; + } + + // Try to find the internal model + const internalModel = modelForGroupKind(model.group, model.kind); + if (!internalModel) { + // CRD not found - log warning and skip + // eslint-disable-next-line no-console + console.warn( + `Could not find model (CRD) for group "${model.group}" and kind "${model.kind}". Resource will be skipped.`, + ); + return null; + } + + const reference = referenceForModel(internalModel); + return { namespace, kind: reference, ...opts }; +}; + const DataModelExtension: React.FC = ({ dataModelFactory }) => { - const dataModelContext = React.useContext(ModelContext); - const { id, priority, resources } = dataModelFactory; + const dataModelContext = useContext(ModelContext); + const { id, priority, resources: rawResources } = dataModelFactory; const workloadKeys = useDeepCompareMemoize(dataModelFactory.workloadKeys); - const extensionContext = React.useRef({ + const { resolved: resolvedResources, isGeneric } = useResolvedResources( + rawResources, + dataModelContext.namespace, + ); + + // Convert WatchK8sResourcesGeneric to WatchK8sResources if needed + const finalResources = useMemo | undefined>(() => { + if (!resolvedResources) { + return undefined; + } + + if (isGeneric) { + // Resources are in WatchK8sResourcesGeneric format, need to be converted + const genericResources = resolvedResources as WatchK8sResourcesGeneric; + const converted: WatchK8sResources = {}; + + Object.entries(genericResources).forEach(([key, resource]) => { + const flattenedResource = convertGenericResource( + dataModelContext.namespace, + resource?.model, + resource?.opts, + ); + if (flattenedResource) { + converted[key] = flattenedResource; + } + }); + + return converted; + } + + // Already in the correct format + return resolvedResources as WatchK8sResources; + }, [resolvedResources, isGeneric, dataModelContext.namespace]); + + const extensionContext = useRef({ priority, workloadKeys, - resources, + resources: undefined, }); - React.useEffect(() => { + useEffect(() => { const storedContext = dataModelContext.getExtension(id); if (!storedContext) { extensionContext.current = { priority, workloadKeys, - resources, + resources: finalResources, }; dataModelContext.updateExtension(id, extensionContext.current); @@ -73,7 +142,7 @@ const DataModelExtension: React.FC = ({ dataModelFactor dataModelContext.updateExtension(id, extensionContext.current); } } - }, [dataModelContext, dataModelFactory, id, priority, resources, workloadKeys]); + }, [dataModelContext, dataModelFactory, id, priority, finalResources, workloadKeys]); return null; }; diff --git a/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx b/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx index 8f62dd7236d..a10be831122 100644 --- a/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx +++ b/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx @@ -10,7 +10,7 @@ import { referenceForExtensionModel, referenceForModel, } from '@console/internal/module/k8s'; -import { LoadedExtension, useExtensions } from '@console/plugin-sdk/src'; +import { LoadedExtension, useExtensions } from '@console/plugin-sdk'; import { isTopologyDataModelFactory, TopologyDataModelFactory } from '../extensions/topology'; import DataModelExtension from './DataModelExtension'; import { ModelContext, ExtensibleModel } from './ModelContext'; @@ -58,12 +58,27 @@ export const getNamespacedDynamicModelFactories = ( extensions: LoadedExtension[], ) => extensions.map((extension) => { + const { resources } = extension.properties; + + // If resources is a CodeRef (function), keep it as-is for resolution in DataModelExtension + if (typeof resources === 'function') { + return { + ...extension, + properties: { + ...extension.properties, + // Keep the original CodeRef - it will be resolved by useResolvedResources hook + resources, + }, + }; + } + + // Static WatchK8sResourcesGeneric - convert to function format for legacy compatibility return { ...extension, properties: { ...extension.properties, resources: (namespace: string) => - Object.entries(extension.properties.resources || {}).reduce((acc, [key, resource]) => { + Object.entries(resources || {}).reduce((acc, [key, resource]: [string, any]) => { const flattenedResource = flattenResource( namespace, extension, diff --git a/frontend/packages/topology/src/data-transforms/ModelContext.ts b/frontend/packages/topology/src/data-transforms/ModelContext.ts index 679ed16fc1f..0ced4282ca9 100644 --- a/frontend/packages/topology/src/data-transforms/ModelContext.ts +++ b/frontend/packages/topology/src/data-transforms/ModelContext.ts @@ -18,7 +18,7 @@ import { export type ModelExtensionContext = { priority: number; - resources?: (namespace: string) => WatchK8sResources; + resources?: WatchK8sResources; workloadKeys?: string[]; dataModelGetter?: TopologyDataModelGetter; dataModelDepicter?: TopologyDataModelDepicted; @@ -98,7 +98,7 @@ export class ExtensibleModel { const extensionKeys = Object.keys(this.extensions); this.watchedResources = extensionKeys.reduce((acc, key) => { if (this.extensions[key].resources) { - const resList = this.extensions[key].resources(this.namespace); + const resList = this.extensions[key].resources; Object.keys(resList).forEach((resKey) => { if (!acc[resKey]) { acc[resKey] = resList[resKey]; diff --git a/frontend/packages/topology/src/hooks/useTopologyDataModelFactory.ts b/frontend/packages/topology/src/hooks/useTopologyDataModelFactory.ts new file mode 100644 index 00000000000..4d24f9267cc --- /dev/null +++ b/frontend/packages/topology/src/hooks/useTopologyDataModelFactory.ts @@ -0,0 +1,101 @@ +import { useState, useEffect } from 'react'; +import { WatchK8sResources, WatchK8sResourcesGeneric } from '@console/dynamic-plugin-sdk'; +import { CodeRef } from '@console/dynamic-plugin-sdk/src/types'; + +/** + * Resources type that can be: + * 1. Static WatchK8sResourcesGeneric (from dynamic plugin SDK) + * 2. CodeRef<() => Promise> (from dynamic plugin SDK, for dynamic resources) + * 3. Function (namespace: string) => WatchK8sResources (from old internal plugin system or converted dynamic plugins) + */ +export type TopologyResourcesType = + | WatchK8sResourcesGeneric + | CodeRef<() => Promise> + | ((namespace: string) => WatchK8sResources); + +/** + * Hook to resolve resources from TopologyDataModelFactory extension. + * Handles: + * - Static WatchK8sResourcesGeneric objects + * - Dynamic CodeRef<() => Promise> for plugins that need runtime fetching + * - Legacy/converted function format (namespace: string) => WatchK8sResources + * + * @param resources - Resources in any of the supported formats + * @param namespace - Current namespace (needed for legacy function format) + * @returns Object with resolved resources and whether they're in Generic format (need conversion) + */ +export const useResolvedResources = ( + resources?: TopologyResourcesType, + namespace?: string, +): { + resolved: WatchK8sResources | WatchK8sResourcesGeneric | undefined; + isGeneric: boolean; +} => { + const [resolvedResources, setResolvedResources] = useState< + WatchK8sResources | WatchK8sResourcesGeneric | undefined + >(undefined); + const [isGeneric, setIsGeneric] = useState(false); + const [loading, setLoading] = useState(true); + + useEffect(() => { + if (!resources) { + setResolvedResources(undefined); + setIsGeneric(false); + setLoading(false); + return; + } + + if (typeof resources === 'function') { + // Check if it's a legacy function (namespace: string) => WatchK8sResources + // or a CodeRef () => Promise + // We can distinguish by checking the function length (legacy has 1 param, CodeRef has 0) + if (resources.length === 1) { + // Legacy/converted format: (namespace: string) => WatchK8sResources + if (namespace) { + try { + const result = (resources as (namespace: string) => WatchK8sResources)(namespace); + setResolvedResources(result); + setIsGeneric(false); // Already converted + } catch (error) { + // eslint-disable-next-line no-console + console.error('Failed to resolve legacy topology resources:', error); + setResolvedResources(undefined); + setIsGeneric(false); + } + } else { + setResolvedResources(undefined); + setIsGeneric(false); + } + setLoading(false); + } else { + // CodeRef format: () => Promise + setLoading(true); + const fetchResources = async () => { + try { + const codeRef = (resources as unknown) as () => Promise; + const result = await codeRef(); + setResolvedResources(result); + setIsGeneric(true); // Needs conversion + } catch (error) { + // eslint-disable-next-line no-console + console.error('Failed to resolve dynamic topology resources:', error); + setResolvedResources(undefined); + setIsGeneric(false); + } finally { + setLoading(false); + } + }; + fetchResources(); + } + } else { + // Static WatchK8sResourcesGeneric object + setResolvedResources(resources as WatchK8sResourcesGeneric); + setIsGeneric(true); // Needs conversion + setLoading(false); + } + }, [resources, namespace]); + + return loading + ? { resolved: undefined, isGeneric: false } + : { resolved: resolvedResources, isGeneric }; +}; From 0dbd7a8bd035d981eb66ce932b7ba38cbc8de2cd Mon Sep 17 00:00:00 2001 From: Leo Li <36619969+Leo6Leo@users.noreply.github.com> Date: Tue, 28 Oct 2025 15:01:42 -0400 Subject: [PATCH 03/16] Apply suggestions from code review Co-authored-by: logonoff --- .../knative-plugin/src/utils/get-knative-resources.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/packages/knative-plugin/src/utils/get-knative-resources.ts b/frontend/packages/knative-plugin/src/utils/get-knative-resources.ts index 9bfcb685165..afcb0110b80 100644 --- a/frontend/packages/knative-plugin/src/utils/get-knative-resources.ts +++ b/frontend/packages/knative-plugin/src/utils/get-knative-resources.ts @@ -457,7 +457,7 @@ export const getKnativeServingResources = () => model: { group: 'serving.knative.dev', version: 'v1beta1', kind: 'DomainMapping' }, opts: { isList: true, optional: true, namespaced: true }, }, - }); + } satisfies WatchK8sResourcesGeneric); export const getKnativeEventingResources = async () => { // Fetch dynamic event sources and channels at runtime @@ -469,7 +469,7 @@ export const getKnativeEventingResources = async () => { acc[ref] = { model: { group: model.apiGroup, version: model.apiVersion, kind: model.kind }, opts: { isList: true, optional: true, namespaced: true }, - }; + } satisfies WatchK8sResourcesGeneric; return acc; }, {}); @@ -478,7 +478,7 @@ export const getKnativeEventingResources = async () => { acc[ref] = { model: { group: model.apiGroup, version: model.apiVersion, kind: model.kind }, opts: { isList: true, optional: true, namespaced: true }, - }; + } satisfies WatchK8sResourcesGeneric; return acc; }, {}); @@ -497,7 +497,7 @@ export const getKnativeEventingResources = async () => { }, ...dynamicEventSources, ...dynamicChannels, - }; + } satisfies WatchK8sResourcesGeneric; }; export const getKnativeEventingKameletsResources = () => @@ -518,4 +518,4 @@ export const getKnativeEventingKameletsResources = () => model: { group: 'camel.apache.org', version: 'v1alpha1', kind: 'Kamelet' }, opts: { isList: true, optional: true, namespaced: true }, }, - }); + } satisfies WatchK8sResourcesGeneric); From d16dafef5c5eb4fee7f28914a13c47f91e6fd0dd Mon Sep 17 00:00:00 2001 From: Leo6Leo <36619969+Leo6Leo@users.noreply.github.com> Date: Tue, 28 Oct 2025 15:13:37 -0400 Subject: [PATCH 04/16] fix: fix the review comments from @logonoff --- .../data-transforms/DataModelExtension.tsx | 5 +- .../src/data-transforms/DataModelProvider.tsx | 90 +------------------ 2 files changed, 6 insertions(+), 89 deletions(-) diff --git a/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx b/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx index 38890a76aca..de4a7ca021f 100644 --- a/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx +++ b/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx @@ -3,6 +3,7 @@ import { WatchK8sResources, WatchK8sResourcesGeneric, WatchK8sResource, + TopologyDataModelFactory as DynamicTopologyDataModelFactory, } from '@console/dynamic-plugin-sdk'; import { referenceForModel, modelForGroupKind } from '@console/internal/module/k8s'; import { useDeepCompareMemoize } from '@console/shared'; @@ -11,7 +12,9 @@ import { useResolvedResources } from '../hooks/useTopologyDataModelFactory'; import { ModelContext, ExtensibleModel, ModelExtensionContext } from './ModelContext'; interface DataModelExtensionProps { - dataModelFactory: TopologyDataModelFactory['properties']; + dataModelFactory: + | TopologyDataModelFactory['properties'] + | DynamicTopologyDataModelFactory['properties']; } /** diff --git a/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx b/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx index a10be831122..b9adee581f1 100644 --- a/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx +++ b/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx @@ -1,16 +1,9 @@ import * as React from 'react'; import { - ExtensionK8sGroupKindModel, isTopologyDataModelFactory as isDynamicTopologyDataModelFactory, TopologyDataModelFactory as DynamicTopologyDataModelFactory, - WatchK8sResource, } from '@console/dynamic-plugin-sdk'; -import { - modelForGroupKind, - referenceForExtensionModel, - referenceForModel, -} from '@console/internal/module/k8s'; -import { LoadedExtension, useExtensions } from '@console/plugin-sdk'; +import { useExtensions } from '@console/plugin-sdk'; import { isTopologyDataModelFactory, TopologyDataModelFactory } from '../extensions/topology'; import DataModelExtension from './DataModelExtension'; import { ModelContext, ExtensibleModel } from './ModelContext'; @@ -21,80 +14,6 @@ interface DataModelProviderProps { children?: React.ReactNode; } -const flattenResource = ( - namespace: string, - extension: LoadedExtension, - resourceKey: string, - model?: ExtensionK8sGroupKindModel, - opts = {} as Partial, -) => { - if (!model) { - return { namespace, ...opts }; - } - - if (model.version) { - const extensionReference = referenceForExtensionModel(model); // requires model.version - return { namespace, kind: extensionReference, ...opts }; - } - - // If can't find reference for an extention model, fall back to internal reference - const internalModel = modelForGroupKind(model.group, model.kind); // Return null for CRDs - if (!internalModel) { - // eslint-disable-next-line no-console - console.warn( - `Plugin "${extension.pluginID}": Could not find model (CRD) for group "${model.group}" and kind "${model.kind}" to determinate version. Please add a required flag to the extension to suppress this warning. The resource "${resourceKey}" will not be loaded and ignored in the topology view for now:`, - extension, - resourceKey, - model, - opts, - ); - return null; - } - const internalReference = referenceForModel(internalModel); - return { namespace, kind: internalReference, ...opts }; -}; - -export const getNamespacedDynamicModelFactories = ( - extensions: LoadedExtension[], -) => - extensions.map((extension) => { - const { resources } = extension.properties; - - // If resources is a CodeRef (function), keep it as-is for resolution in DataModelExtension - if (typeof resources === 'function') { - return { - ...extension, - properties: { - ...extension.properties, - // Keep the original CodeRef - it will be resolved by useResolvedResources hook - resources, - }, - }; - } - - // Static WatchK8sResourcesGeneric - convert to function format for legacy compatibility - return { - ...extension, - properties: { - ...extension.properties, - resources: (namespace: string) => - Object.entries(resources || {}).reduce((acc, [key, resource]: [string, any]) => { - const flattenedResource = flattenResource( - namespace, - extension, - key, - resource?.model, - resource?.opts, - ); - if (flattenedResource) { - acc[key] = flattenedResource; - } - return acc; - }, {}), - }, - }; - }); - const DataModelProvider: React.FC = ({ namespace, children }) => { const [model, setModel] = React.useState(new ExtensibleModel(namespace)); @@ -107,16 +26,11 @@ const DataModelProvider: React.FC = ({ namespace, childr isDynamicTopologyDataModelFactory, ); - const namespacedDynamicFactories = React.useMemo( - () => getNamespacedDynamicModelFactories(dynamicModelFactories), - [dynamicModelFactories], - ); - return ( {namespace && ( <> - {[...namespacedDynamicFactories, ...modelFactories].map((factory) => ( + {[...dynamicModelFactories, ...modelFactories].map((factory) => ( ))} From 395122d6d85b72f714e664be56189b614a69d887 Mon Sep 17 00:00:00 2001 From: Leo6Leo <36619969+Leo6Leo@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:50:40 -0400 Subject: [PATCH 05/16] OCPBUGS-4806: Convert knative topology resources from CodeRef to static definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces dynamic CodeRef-based resource definitions with inline static definitions for knative-serving and kamelets topology model factories, removing the need for runtime resolution. Adds compatibility layer for converting dynamic model factories to internal plugin format. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../knative-plugin/console-extensions.json | 38 ++++++++++++- .../src/utils/get-knative-resources.ts | 56 ++----------------- .../src/data-transforms/DataModelProvider.tsx | 25 +++++++++ 3 files changed, 67 insertions(+), 52 deletions(-) diff --git a/frontend/packages/knative-plugin/console-extensions.json b/frontend/packages/knative-plugin/console-extensions.json index 88d47aa9f61..5efedae81dd 100644 --- a/frontend/packages/knative-plugin/console-extensions.json +++ b/frontend/packages/knative-plugin/console-extensions.json @@ -2015,7 +2015,26 @@ "id": "knative-serving-topology-model-factory", "priority": 100, "resources": { - "$codeRef": "getKnativeResources.getKnativeServingResources" + "revisions": { + "model": { "group": "serving.knative.dev", "version": "v1", "kind": "Revision" }, + "opts": { "isList": true, "optional": true, "namespaced": true } + }, + "configurations": { + "model": { "group": "serving.knative.dev", "version": "v1", "kind": "Configuration" }, + "opts": { "isList": true, "optional": true, "namespaced": true } + }, + "ksroutes": { + "model": { "group": "serving.knative.dev", "version": "v1", "kind": "Route" }, + "opts": { "isList": true, "optional": true, "namespaced": true } + }, + "ksservices": { + "model": { "group": "serving.knative.dev", "version": "v1", "kind": "Service" }, + "opts": { "isList": true, "optional": true, "namespaced": true } + }, + "domainmappings": { + "model": { "group": "serving.knative.dev", "version": "v1beta1", "kind": "DomainMapping" }, + "opts": { "isList": true, "optional": true, "namespaced": true } + } }, "workloadKeys": ["ksservices"], "getDataModel": { @@ -2061,7 +2080,22 @@ "id": "knative-kamelets-topology-model-factory", "priority": 100, "resources": { - "$codeRef": "getKnativeResources.getKnativeEventingKameletsResources" + "integrations": { + "model": { "group": "camel.apache.org", "version": "v1", "kind": "Integration" }, + "opts": { "isList": true, "optional": true, "namespaced": true } + }, + "kameletbindings": { + "model": { "group": "camel.apache.org", "version": "v1alpha1", "kind": "KameletBinding" }, + "opts": { "isList": true, "optional": true, "namespaced": true } + }, + "domainmappings": { + "model": { "group": "serving.knative.dev", "version": "v1beta1", "kind": "DomainMapping" }, + "opts": { "isList": true, "optional": true, "namespaced": true } + }, + "kamelets": { + "model": { "group": "camel.apache.org", "version": "v1alpha1", "kind": "Kamelet" }, + "opts": { "isList": true, "optional": true, "namespaced": true } + } }, "workloadKeys": ["kameletbindings"], "getDataModel": { diff --git a/frontend/packages/knative-plugin/src/utils/get-knative-resources.ts b/frontend/packages/knative-plugin/src/utils/get-knative-resources.ts index afcb0110b80..3fa064de37f 100644 --- a/frontend/packages/knative-plugin/src/utils/get-knative-resources.ts +++ b/frontend/packages/knative-plugin/src/utils/get-knative-resources.ts @@ -1,5 +1,5 @@ import * as _ from 'lodash'; -import { WatchK8sResources } from '@console/dynamic-plugin-sdk'; +import { WatchK8sResources, WatchK8sResourcesGeneric } from '@console/dynamic-plugin-sdk'; import { FirehoseResource } from '@console/internal/components/utils'; import { K8sResourceKind, PodKind, referenceForModel } from '@console/internal/module/k8s'; import { GLOBAL_OPERATOR_NS, KNATIVE_SERVING_LABEL } from '../const'; @@ -435,30 +435,6 @@ export const getSinkableResources = (namespace: string): FirehoseResource[] => { : []; }; -export const getKnativeServingResources = () => - Promise.resolve({ - revisions: { - model: { group: 'serving.knative.dev', version: 'v1', kind: 'Revision' }, - opts: { isList: true, optional: true, namespaced: true }, - }, - configurations: { - model: { group: 'serving.knative.dev', version: 'v1', kind: 'Configuration' }, - opts: { isList: true, optional: true, namespaced: true }, - }, - ksroutes: { - model: { group: 'serving.knative.dev', version: 'v1', kind: 'Route' }, - opts: { isList: true, optional: true, namespaced: true }, - }, - ksservices: { - model: { group: 'serving.knative.dev', version: 'v1', kind: 'Service' }, - opts: { isList: true, optional: true, namespaced: true }, - }, - domainmappings: { - model: { group: 'serving.knative.dev', version: 'v1beta1', kind: 'DomainMapping' }, - opts: { isList: true, optional: true, namespaced: true }, - }, - } satisfies WatchK8sResourcesGeneric); - export const getKnativeEventingResources = async () => { // Fetch dynamic event sources and channels at runtime const eventSourceModels = await fetchEventSourcesCrd(); @@ -469,18 +445,18 @@ export const getKnativeEventingResources = async () => { acc[ref] = { model: { group: model.apiGroup, version: model.apiVersion, kind: model.kind }, opts: { isList: true, optional: true, namespaced: true }, - } satisfies WatchK8sResourcesGeneric; + }; return acc; - }, {}); + }, {} as WatchK8sResourcesGeneric); const dynamicChannels = eventingChannels.reduce((acc, model) => { const ref = referenceForModel(model); acc[ref] = { model: { group: model.apiGroup, version: model.apiVersion, kind: model.kind }, opts: { isList: true, optional: true, namespaced: true }, - } satisfies WatchK8sResourcesGeneric; + }; return acc; - }, {}); + }, {} as WatchK8sResourcesGeneric); return { eventingsubscription: { @@ -497,25 +473,5 @@ export const getKnativeEventingResources = async () => { }, ...dynamicEventSources, ...dynamicChannels, - } satisfies WatchK8sResourcesGeneric; + }; }; - -export const getKnativeEventingKameletsResources = () => - Promise.resolve({ - integrations: { - model: { group: 'camel.apache.org', version: 'v1', kind: 'Integration' }, - opts: { isList: true, optional: true, namespaced: true }, - }, - kameletbindings: { - model: { group: 'camel.apache.org', version: 'v1alpha1', kind: 'KameletBinding' }, - opts: { isList: true, optional: true, namespaced: true }, - }, - domainmappings: { - model: { group: 'serving.knative.dev', version: 'v1beta1', kind: 'DomainMapping' }, - opts: { isList: true, optional: true, namespaced: true }, - }, - kamelets: { - model: { group: 'camel.apache.org', version: 'v1alpha1', kind: 'Kamelet' }, - opts: { isList: true, optional: true, namespaced: true }, - }, - } satisfies WatchK8sResourcesGeneric); diff --git a/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx b/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx index b9adee581f1..b956696cfb7 100644 --- a/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx +++ b/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { isTopologyDataModelFactory as isDynamicTopologyDataModelFactory, TopologyDataModelFactory as DynamicTopologyDataModelFactory, + WatchK8sResources, } from '@console/dynamic-plugin-sdk'; import { useExtensions } from '@console/plugin-sdk'; import { isTopologyDataModelFactory, TopologyDataModelFactory } from '../extensions/topology'; @@ -9,6 +10,30 @@ import DataModelExtension from './DataModelExtension'; import { ModelContext, ExtensibleModel } from './ModelContext'; import TopologyDataRetriever from './TopologyDataRetriever'; +/** + * Converts dynamic model factories (with WatchK8sResourcesGeneric) to the internal plugin format + * (with resources as a function that takes namespace and returns WatchK8sResources) + */ +export function getNamespacedDynamicModelFactories( + dynamicFactories: DynamicTopologyDataModelFactory[], +): TopologyDataModelFactory[] { + return dynamicFactories + .filter((factory) => factory.properties.resources) + .map((factory) => ({ + type: 'Topology/DataModelFactory' as const, + properties: { + ...factory.properties, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + resources: (_namespace: string): WatchK8sResources => { + // Dynamic factories use WatchK8sResourcesGeneric which is handled differently + // This is a compatibility layer for the legacy Firehose-based ApplicationDropdown + // Dynamic factories are properly handled in DataModelExtension component + return {}; + }, + }, + })); +} + interface DataModelProviderProps { namespace: string; children?: React.ReactNode; From 9a51df4b1d47e90331c6a0c3028d4047cb0952fc Mon Sep 17 00:00:00 2001 From: Leo6Leo <36619969+Leo6Leo@users.noreply.github.com> Date: Mon, 3 Nov 2025 15:27:16 -0500 Subject: [PATCH 06/16] OCPBUGS-4806: Remove static topology data model factory extensions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor topology package to remove static extension support and rely exclusively on dynamic plugin SDK for topology data model factories. Key changes: - Remove TopologyDataModelFactory extension interface and related types - Simplify ApplicationDropdown to use only base watched resources - Remove legacy function format support in useTopologyDataModelFactory - Eliminate conversion layer between dynamic and static factories - Update DataModelProvider to handle only dynamic extensions 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../dropdowns/ApplicationDropdown.tsx | 31 +------ .../data-transforms/DataModelExtension.tsx | 14 +-- .../src/data-transforms/DataModelProvider.tsx | 29 +------ .../topology/src/extensions/topology.ts | 30 ------- .../src/hooks/useTopologyDataModelFactory.ts | 86 ++++++------------- 5 files changed, 36 insertions(+), 154 deletions(-) diff --git a/frontend/packages/topology/src/components/dropdowns/ApplicationDropdown.tsx b/frontend/packages/topology/src/components/dropdowns/ApplicationDropdown.tsx index ce9e43a4c9e..c26a8055c88 100644 --- a/frontend/packages/topology/src/components/dropdowns/ApplicationDropdown.tsx +++ b/frontend/packages/topology/src/components/dropdowns/ApplicationDropdown.tsx @@ -1,16 +1,9 @@ import * as React from 'react'; import { useTranslation } from 'react-i18next'; -import { - isTopologyDataModelFactory as isDynamicTopologyDataModelFactory, - TopologyDataModelFactory as DynamicTopologyDataModelFactory, -} from '@console/dynamic-plugin-sdk'; import { Firehose } from '@console/internal/components/utils'; -import { useExtensions } from '@console/plugin-sdk/src'; import { ResourceDropdown } from '@console/shared'; import { ResourceDropdownProps } from '../../../../console-shared/src/components/dropdown/ResourceDropdown'; -import { getNamespacedDynamicModelFactories } from '../../data-transforms/DataModelProvider'; import { getBaseWatchedResources } from '../../data-transforms/transform-utils'; -import { isTopologyDataModelFactory, TopologyDataModelFactory } from '../../extensions'; type ApplicationDropdownProps = Omit & { namespace?: string; @@ -18,32 +11,16 @@ type ApplicationDropdownProps = Omit = ({ namespace, ...props }) => { const { t } = useTranslation(); - const modelFactories = useExtensions(isTopologyDataModelFactory); - const dynamicModelFactories = useExtensions( - isDynamicTopologyDataModelFactory, - ); - - const namespacedDynamicFactories = React.useMemo( - () => getNamespacedDynamicModelFactories(dynamicModelFactories), - [dynamicModelFactories], - ); const resources = React.useMemo(() => { - let watchedBaseResources = getBaseWatchedResources(namespace); - [...modelFactories, ...namespacedDynamicFactories].forEach((modelFactory) => { - const factoryResources = modelFactory.properties.resources?.(namespace); - if (factoryResources) { - watchedBaseResources = { - ...factoryResources, - ...watchedBaseResources, - }; - } - }); + // Use only base watched resources since dynamic factories are handled separately + // and ApplicationDropdown primarily needs the base resources for application labels + const watchedBaseResources = getBaseWatchedResources(namespace); return Object.keys(watchedBaseResources).map((key) => ({ ...watchedBaseResources[key], prop: key, })); - }, [namespacedDynamicFactories, modelFactories, namespace]); + }, [namespace]); return ( diff --git a/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx b/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx index de4a7ca021f..8e2764f4829 100644 --- a/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx +++ b/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx @@ -7,14 +7,11 @@ import { } from '@console/dynamic-plugin-sdk'; import { referenceForModel, modelForGroupKind } from '@console/internal/module/k8s'; import { useDeepCompareMemoize } from '@console/shared'; -import { TopologyDataModelFactory } from '../extensions/topology'; import { useResolvedResources } from '../hooks/useTopologyDataModelFactory'; import { ModelContext, ExtensibleModel, ModelExtensionContext } from './ModelContext'; interface DataModelExtensionProps { - dataModelFactory: - | TopologyDataModelFactory['properties'] - | DynamicTopologyDataModelFactory['properties']; + dataModelFactory: DynamicTopologyDataModelFactory['properties']; } /** @@ -49,12 +46,9 @@ const DataModelExtension: React.FC = ({ dataModelFactor const dataModelContext = useContext(ModelContext); const { id, priority, resources: rawResources } = dataModelFactory; const workloadKeys = useDeepCompareMemoize(dataModelFactory.workloadKeys); - const { resolved: resolvedResources, isGeneric } = useResolvedResources( - rawResources, - dataModelContext.namespace, - ); + const { resolved: resolvedResources, isGeneric } = useResolvedResources(rawResources); - // Convert WatchK8sResourcesGeneric to WatchK8sResources if needed + // Convert WatchK8sResourcesGeneric to WatchK8sResources const finalResources = useMemo | undefined>(() => { if (!resolvedResources) { return undefined; @@ -79,7 +73,7 @@ const DataModelExtension: React.FC = ({ dataModelFactor return converted; } - // Already in the correct format + // Should not reach here as isGeneric is always true now return resolvedResources as WatchK8sResources; }, [resolvedResources, isGeneric, dataModelContext.namespace]); diff --git a/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx b/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx index b956696cfb7..07df3293507 100644 --- a/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx +++ b/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx @@ -2,38 +2,12 @@ import * as React from 'react'; import { isTopologyDataModelFactory as isDynamicTopologyDataModelFactory, TopologyDataModelFactory as DynamicTopologyDataModelFactory, - WatchK8sResources, } from '@console/dynamic-plugin-sdk'; import { useExtensions } from '@console/plugin-sdk'; -import { isTopologyDataModelFactory, TopologyDataModelFactory } from '../extensions/topology'; import DataModelExtension from './DataModelExtension'; import { ModelContext, ExtensibleModel } from './ModelContext'; import TopologyDataRetriever from './TopologyDataRetriever'; -/** - * Converts dynamic model factories (with WatchK8sResourcesGeneric) to the internal plugin format - * (with resources as a function that takes namespace and returns WatchK8sResources) - */ -export function getNamespacedDynamicModelFactories( - dynamicFactories: DynamicTopologyDataModelFactory[], -): TopologyDataModelFactory[] { - return dynamicFactories - .filter((factory) => factory.properties.resources) - .map((factory) => ({ - type: 'Topology/DataModelFactory' as const, - properties: { - ...factory.properties, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - resources: (_namespace: string): WatchK8sResources => { - // Dynamic factories use WatchK8sResourcesGeneric which is handled differently - // This is a compatibility layer for the legacy Firehose-based ApplicationDropdown - // Dynamic factories are properly handled in DataModelExtension component - return {}; - }, - }, - })); -} - interface DataModelProviderProps { namespace: string; children?: React.ReactNode; @@ -46,7 +20,6 @@ const DataModelProvider: React.FC = ({ namespace, childr setModel(new ExtensibleModel(namespace)); }, [namespace]); - const modelFactories = useExtensions(isTopologyDataModelFactory); const dynamicModelFactories = useExtensions( isDynamicTopologyDataModelFactory, ); @@ -55,7 +28,7 @@ const DataModelProvider: React.FC = ({ namespace, childr {namespace && ( <> - {[...dynamicModelFactories, ...modelFactories].map((factory) => ( + {dynamicModelFactories.map((factory) => ( ))} diff --git a/frontend/packages/topology/src/extensions/topology.ts b/frontend/packages/topology/src/extensions/topology.ts index 5c535777f36..7e4342136f0 100644 --- a/frontend/packages/topology/src/extensions/topology.ts +++ b/frontend/packages/topology/src/extensions/topology.ts @@ -1,14 +1,10 @@ import { TopologyQuadrant } from '@patternfly/react-topology'; -import { WatchK8sResources } from '@console/dynamic-plugin-sdk'; import { CodeRef } from '@console/dynamic-plugin-sdk/src/types'; import { Extension } from '@console/plugin-sdk/src/typings/base'; import { TopologyApplyDisplayOptions, - TopologyDataModelDepicted, - TopologyDataModelGetter, TopologyDisplayOption, ViewComponentFactory, - TopologyDataModelReconciler, TopologyDecoratorGetter, } from '../topology-types'; @@ -18,23 +14,6 @@ namespace ExtensionProperties { getFactory: CodeRef; } - export interface TopologyDataModelFactory { - /** Unique ID for the factory. */ - id: string; - /** Priority for the factory */ - priority: number; - /** Resources to be fetched from useK8sWatchResources hook. */ - resources?: (namespace: string) => WatchK8sResources; - /** Keys in resources containing workloads. */ - workloadKeys?: string[]; - /** Getter for the data model factory */ - getDataModel?: CodeRef; - /** Getter for function to determine if a resource is depicted by this model factory */ - isResourceDepicted?: CodeRef; - /** Getter for function to reconcile data model after all extensions' models have loaded */ - getDataModelReconciler?: CodeRef; - } - export interface TopologyDisplayFilters { // Getter for topology filters specific to the extension getTopologyFilters: CodeRef<() => TopologyDisplayOption[]>; @@ -55,11 +34,6 @@ export interface TopologyComponentFactory type: 'Topology/ComponentFactory'; } -export interface TopologyDataModelFactory - extends Extension { - type: 'Topology/DataModelFactory'; -} - export interface TopologyDisplayFilters extends Extension { type: 'Topology/DisplayFilters'; @@ -74,10 +48,6 @@ export const isTopologyComponentFactory = (e: Extension): e is TopologyComponent return e.type === 'Topology/ComponentFactory'; }; -export const isTopologyDataModelFactory = (e: Extension): e is TopologyDataModelFactory => { - return e.type === 'Topology/DataModelFactory'; -}; - export const isTopologyDisplayFilters = (e: Extension): e is TopologyDisplayFilters => { return e.type === 'Topology/DisplayFilters'; }; diff --git a/frontend/packages/topology/src/hooks/useTopologyDataModelFactory.ts b/frontend/packages/topology/src/hooks/useTopologyDataModelFactory.ts index 4d24f9267cc..0b62d468e56 100644 --- a/frontend/packages/topology/src/hooks/useTopologyDataModelFactory.ts +++ b/frontend/packages/topology/src/hooks/useTopologyDataModelFactory.ts @@ -1,101 +1,69 @@ import { useState, useEffect } from 'react'; -import { WatchK8sResources, WatchK8sResourcesGeneric } from '@console/dynamic-plugin-sdk'; +import { WatchK8sResourcesGeneric } from '@console/dynamic-plugin-sdk'; import { CodeRef } from '@console/dynamic-plugin-sdk/src/types'; /** * Resources type that can be: * 1. Static WatchK8sResourcesGeneric (from dynamic plugin SDK) * 2. CodeRef<() => Promise> (from dynamic plugin SDK, for dynamic resources) - * 3. Function (namespace: string) => WatchK8sResources (from old internal plugin system or converted dynamic plugins) */ export type TopologyResourcesType = | WatchK8sResourcesGeneric - | CodeRef<() => Promise> - | ((namespace: string) => WatchK8sResources); + | CodeRef<() => Promise>; /** * Hook to resolve resources from TopologyDataModelFactory extension. * Handles: * - Static WatchK8sResourcesGeneric objects * - Dynamic CodeRef<() => Promise> for plugins that need runtime fetching - * - Legacy/converted function format (namespace: string) => WatchK8sResources * * @param resources - Resources in any of the supported formats - * @param namespace - Current namespace (needed for legacy function format) - * @returns Object with resolved resources and whether they're in Generic format (need conversion) + * @returns Object with resolved resources (always in Generic format) */ export const useResolvedResources = ( resources?: TopologyResourcesType, - namespace?: string, -): { - resolved: WatchK8sResources | WatchK8sResourcesGeneric | undefined; - isGeneric: boolean; -} => { - const [resolvedResources, setResolvedResources] = useState< - WatchK8sResources | WatchK8sResourcesGeneric | undefined - >(undefined); - const [isGeneric, setIsGeneric] = useState(false); +): { resolved: WatchK8sResourcesGeneric | undefined; isGeneric: boolean } => { + const [resolvedResources, setResolvedResources] = useState( + undefined, + ); const [loading, setLoading] = useState(true); useEffect(() => { if (!resources) { setResolvedResources(undefined); - setIsGeneric(false); setLoading(false); return; } if (typeof resources === 'function') { - // Check if it's a legacy function (namespace: string) => WatchK8sResources - // or a CodeRef () => Promise - // We can distinguish by checking the function length (legacy has 1 param, CodeRef has 0) - if (resources.length === 1) { - // Legacy/converted format: (namespace: string) => WatchK8sResources - if (namespace) { - try { - const result = (resources as (namespace: string) => WatchK8sResources)(namespace); - setResolvedResources(result); - setIsGeneric(false); // Already converted - } catch (error) { - // eslint-disable-next-line no-console - console.error('Failed to resolve legacy topology resources:', error); - setResolvedResources(undefined); - setIsGeneric(false); - } - } else { + // CodeRef format: CodeRef<() => Promise> + // which is a function that returns Promise<() => Promise> + setLoading(true); + const fetchResources = async () => { + try { + const codeRef = (resources as unknown) as CodeRef< + () => Promise + >; + const getResources = await codeRef(); + const result = await getResources(); + setResolvedResources(result); + } catch (error) { + // eslint-disable-next-line no-console + console.error('Failed to resolve dynamic topology resources:', error); setResolvedResources(undefined); - setIsGeneric(false); + } finally { + setLoading(false); } - setLoading(false); - } else { - // CodeRef format: () => Promise - setLoading(true); - const fetchResources = async () => { - try { - const codeRef = (resources as unknown) as () => Promise; - const result = await codeRef(); - setResolvedResources(result); - setIsGeneric(true); // Needs conversion - } catch (error) { - // eslint-disable-next-line no-console - console.error('Failed to resolve dynamic topology resources:', error); - setResolvedResources(undefined); - setIsGeneric(false); - } finally { - setLoading(false); - } - }; - fetchResources(); - } + }; + fetchResources(); } else { // Static WatchK8sResourcesGeneric object setResolvedResources(resources as WatchK8sResourcesGeneric); - setIsGeneric(true); // Needs conversion setLoading(false); } - }, [resources, namespace]); + }, [resources]); return loading ? { resolved: undefined, isGeneric: false } - : { resolved: resolvedResources, isGeneric }; + : { resolved: resolvedResources, isGeneric: true }; }; From 96cb737cb18d16908041763b58a4e17d127d27c9 Mon Sep 17 00:00:00 2001 From: Leo Li <36619969+Leo6Leo@users.noreply.github.com> Date: Tue, 4 Nov 2025 16:20:42 -0500 Subject: [PATCH 07/16] Apply suggestions from code review Co-authored-by: logonoff --- .../topology/src/data-transforms/DataModelExtension.tsx | 2 +- .../packages/topology/src/data-transforms/DataModelProvider.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx b/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx index 8e2764f4829..4907a4bbe94 100644 --- a/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx +++ b/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx @@ -3,7 +3,7 @@ import { WatchK8sResources, WatchK8sResourcesGeneric, WatchK8sResource, - TopologyDataModelFactory as DynamicTopologyDataModelFactory, + TopologyDataModelFactory, } from '@console/dynamic-plugin-sdk'; import { referenceForModel, modelForGroupKind } from '@console/internal/module/k8s'; import { useDeepCompareMemoize } from '@console/shared'; diff --git a/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx b/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx index 07df3293507..1c0450b354f 100644 --- a/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx +++ b/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx @@ -28,7 +28,7 @@ const DataModelProvider: React.FC = ({ namespace, childr {namespace && ( <> - {dynamicModelFactories.map((factory) => ( + {modelFactories.map((factory) => ( ))} From e733bb8eb99193017965bc66def525fbb4361dab Mon Sep 17 00:00:00 2001 From: Leo Li <36619969+Leo6Leo@users.noreply.github.com> Date: Tue, 4 Nov 2025 16:29:05 -0500 Subject: [PATCH 08/16] Update frontend/packages/knative-plugin/src/utils/get-knative-resources.ts Co-authored-by: logonoff --- .../knative-plugin/src/utils/get-knative-resources.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/packages/knative-plugin/src/utils/get-knative-resources.ts b/frontend/packages/knative-plugin/src/utils/get-knative-resources.ts index 3fa064de37f..63ccbe0cc37 100644 --- a/frontend/packages/knative-plugin/src/utils/get-knative-resources.ts +++ b/frontend/packages/knative-plugin/src/utils/get-knative-resources.ts @@ -435,7 +435,7 @@ export const getSinkableResources = (namespace: string): FirehoseResource[] => { : []; }; -export const getKnativeEventingResources = async () => { +export const getKnativeEventingResources = async (): Promise => { // Fetch dynamic event sources and channels at runtime const eventSourceModels = await fetchEventSourcesCrd(); const eventingChannels = await fetchChannelsCrd(); @@ -447,7 +447,7 @@ export const getKnativeEventingResources = async () => { opts: { isList: true, optional: true, namespaced: true }, }; return acc; - }, {} as WatchK8sResourcesGeneric); + }, {}); const dynamicChannels = eventingChannels.reduce((acc, model) => { const ref = referenceForModel(model); @@ -456,7 +456,7 @@ export const getKnativeEventingResources = async () => { opts: { isList: true, optional: true, namespaced: true }, }; return acc; - }, {} as WatchK8sResourcesGeneric); + }, {}); return { eventingsubscription: { From d2041742b56a73a52d75005fbb9a6e460b5e8eac Mon Sep 17 00:00:00 2001 From: Leo6Leo <36619969+Leo6Leo@users.noreply.github.com> Date: Wed, 5 Nov 2025 10:59:11 -0500 Subject: [PATCH 09/16] OCPBUGS-4806: Refactor topology data model to use useResolvedExtensions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace custom useResolvedResources hook with built-in useResolvedExtensions to simplify the topology data model extension handling. This removes the need for manual CodeRef resolution and improves error messaging with plugin context. Changes: - Use useResolvedExtensions instead of useExtensions in DataModelProvider - Remove useTopologyDataModelFactory hook (no longer needed) - Simplify DataModelExtension to work with pre-resolved extensions - Add plugin ID to error messages for better debugging - Use referenceForExtensionModel for better CRD reference resolution 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../data-transforms/DataModelExtension.tsx | 153 ++++++++---------- .../src/data-transforms/DataModelProvider.tsx | 19 ++- .../src/data-transforms/ModelContext.ts | 2 +- .../src/hooks/useTopologyDataModelFactory.ts | 69 -------- 4 files changed, 84 insertions(+), 159 deletions(-) delete mode 100644 frontend/packages/topology/src/hooks/useTopologyDataModelFactory.ts diff --git a/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx b/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx index 4907a4bbe94..7e561f5b257 100644 --- a/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx +++ b/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx @@ -4,14 +4,19 @@ import { WatchK8sResourcesGeneric, WatchK8sResource, TopologyDataModelFactory, + ResolvedExtension, } from '@console/dynamic-plugin-sdk'; -import { referenceForModel, modelForGroupKind } from '@console/internal/module/k8s'; +import { + referenceForModel, + modelForGroupKind, + referenceForExtensionModel, +} from '@console/internal/module/k8s'; import { useDeepCompareMemoize } from '@console/shared'; -import { useResolvedResources } from '../hooks/useTopologyDataModelFactory'; import { ModelContext, ExtensibleModel, ModelExtensionContext } from './ModelContext'; interface DataModelExtensionProps { - dataModelFactory: DynamicTopologyDataModelFactory['properties']; + dataModelFactory: ResolvedExtension['properties']; + pluginID: string; } /** @@ -20,6 +25,8 @@ interface DataModelExtensionProps { */ const convertGenericResource = ( namespace: string, + pluginID: string, + resourceKey: string, model?: { group?: string; version?: string; kind: string }, opts?: Partial, ): WatchK8sResource | null => { @@ -27,55 +34,68 @@ const convertGenericResource = ( return { namespace, ...opts }; } - // Try to find the internal model + // If version is provided, use referenceForExtensionModel directly + if (model.version && model.group) { + const extensionReference = referenceForExtensionModel({ + group: model.group, + version: model.version, + kind: model.kind, + }); + return { namespace, kind: extensionReference, ...opts }; + } + + // Fall back to internal model reference resolution const internalModel = modelForGroupKind(model.group, model.kind); if (!internalModel) { // CRD not found - log warning and skip // eslint-disable-next-line no-console console.warn( - `Could not find model (CRD) for group "${model.group}" and kind "${model.kind}". Resource will be skipped.`, + `Plugin "${pluginID}": Could not find model (CRD) for group "${model.group}" and kind "${model.kind}" to determine version. Please add a required flag to the extension to suppress this warning. The resource "${resourceKey}" will not be loaded and ignored in the topology view for now.`, ); return null; } - const reference = referenceForModel(internalModel); - return { namespace, kind: reference, ...opts }; + const internalReference = referenceForModel(internalModel); + return { namespace, kind: internalReference, ...opts }; }; -const DataModelExtension: React.FC = ({ dataModelFactory }) => { +const DataModelExtension: React.FC = ({ dataModelFactory, pluginID }) => { const dataModelContext = useContext(ModelContext); - const { id, priority, resources: rawResources } = dataModelFactory; + const { + id, + priority, + resources: rawResources, + getDataModel, + isResourceDepicted, + getDataModelReconciler, + } = dataModelFactory; const workloadKeys = useDeepCompareMemoize(dataModelFactory.workloadKeys); - const { resolved: resolvedResources, isGeneric } = useResolvedResources(rawResources); - // Convert WatchK8sResourcesGeneric to WatchK8sResources + // Convert WatchK8sResourcesGeneric to WatchK8sResources with namespace injection const finalResources = useMemo | undefined>(() => { - if (!resolvedResources) { + if (!rawResources) { return undefined; } - if (isGeneric) { - // Resources are in WatchK8sResourcesGeneric format, need to be converted - const genericResources = resolvedResources as WatchK8sResourcesGeneric; - const converted: WatchK8sResources = {}; - - Object.entries(genericResources).forEach(([key, resource]) => { - const flattenedResource = convertGenericResource( - dataModelContext.namespace, - resource?.model, - resource?.opts, - ); - if (flattenedResource) { - converted[key] = flattenedResource; - } - }); - - return converted; - } + // Resources are already resolved by useResolvedExtensions, just need to convert format + const genericResources = rawResources as WatchK8sResourcesGeneric; + const converted: WatchK8sResources = {}; + + Object.entries(genericResources).forEach(([key, resource]) => { + const flattenedResource = convertGenericResource( + dataModelContext.namespace, + pluginID, + key, + resource?.model, + resource?.opts, + ); + if (flattenedResource) { + converted[key] = flattenedResource; + } + }); - // Should not reach here as isGeneric is always true now - return resolvedResources as WatchK8sResources; - }, [resolvedResources, isGeneric, dataModelContext.namespace]); + return converted; + }, [rawResources, dataModelContext.namespace, pluginID]); const extensionContext = useRef({ priority, @@ -86,60 +106,29 @@ const DataModelExtension: React.FC = ({ dataModelFactor useEffect(() => { const storedContext = dataModelContext.getExtension(id); if (!storedContext) { - extensionContext.current = { + // All CodeRefs are already resolved by useResolvedExtensions + const newContext: ModelExtensionContext = { priority, workloadKeys, resources: finalResources, + // These are now direct functions, not CodeRefs that need resolution + dataModelGetter: getDataModel || (() => Promise.resolve({})), + dataModelDepicter: isResourceDepicted || (() => false), + dataModelReconciler: getDataModelReconciler || (() => {}), }; - dataModelContext.updateExtension(id, extensionContext.current); - - const { getDataModel, isResourceDepicted, getDataModelReconciler } = dataModelFactory; - if (getDataModel) { - getDataModel() - .then((getter) => { - extensionContext.current.dataModelGetter = getter; - dataModelContext.updateExtension(id, extensionContext.current); - }) - .catch(() => { - extensionContext.current.dataModelGetter = () => Promise.resolve({}); - dataModelContext.updateExtension(id, extensionContext.current); - }); - } else { - extensionContext.current.dataModelGetter = () => Promise.resolve({}); - dataModelContext.updateExtension(id, extensionContext.current); - } - - if (isResourceDepicted) { - isResourceDepicted() - .then((depicter) => { - extensionContext.current.dataModelDepicter = depicter; - dataModelContext.updateExtension(id, extensionContext.current); - }) - .catch(() => { - extensionContext.current.dataModelDepicter = () => false; - dataModelContext.updateExtension(id, extensionContext.current); - }); - } else { - extensionContext.current.dataModelDepicter = () => false; - dataModelContext.updateExtension(id, extensionContext.current); - } - - if (getDataModelReconciler) { - getDataModelReconciler() - .then((reconciler) => { - extensionContext.current.dataModelReconciler = reconciler; - dataModelContext.updateExtension(id, extensionContext.current); - }) - .catch(() => { - extensionContext.current.dataModelReconciler = () => {}; - dataModelContext.updateExtension(id, extensionContext.current); - }); - } else { - extensionContext.current.dataModelReconciler = () => {}; - dataModelContext.updateExtension(id, extensionContext.current); - } + extensionContext.current = newContext; + dataModelContext.updateExtension(id, newContext); } - }, [dataModelContext, dataModelFactory, id, priority, finalResources, workloadKeys]); + }, [ + dataModelContext, + id, + priority, + finalResources, + workloadKeys, + getDataModel, + isResourceDepicted, + getDataModelReconciler, + ]); return null; }; diff --git a/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx b/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx index 1c0450b354f..ea8a80f74f2 100644 --- a/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx +++ b/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx @@ -2,8 +2,8 @@ import * as React from 'react'; import { isTopologyDataModelFactory as isDynamicTopologyDataModelFactory, TopologyDataModelFactory as DynamicTopologyDataModelFactory, + useResolvedExtensions, } from '@console/dynamic-plugin-sdk'; -import { useExtensions } from '@console/plugin-sdk'; import DataModelExtension from './DataModelExtension'; import { ModelContext, ExtensibleModel } from './ModelContext'; import TopologyDataRetriever from './TopologyDataRetriever'; @@ -20,16 +20,21 @@ const DataModelProvider: React.FC = ({ namespace, childr setModel(new ExtensibleModel(namespace)); }, [namespace]); - const dynamicModelFactories = useExtensions( - isDynamicTopologyDataModelFactory, - ); + // Use useResolvedExtensions to automatically resolve all CodeRefs in the extensions + const [dynamicModelFactories, dynamicResolved] = useResolvedExtensions< + DynamicTopologyDataModelFactory + >(isDynamicTopologyDataModelFactory); return ( - {namespace && ( + {namespace && dynamicResolved && ( <> - {modelFactories.map((factory) => ( - + {dynamicModelFactories.map((factory) => ( + ))} )} diff --git a/frontend/packages/topology/src/data-transforms/ModelContext.ts b/frontend/packages/topology/src/data-transforms/ModelContext.ts index 0ced4282ca9..ab9dd89ed58 100644 --- a/frontend/packages/topology/src/data-transforms/ModelContext.ts +++ b/frontend/packages/topology/src/data-transforms/ModelContext.ts @@ -18,8 +18,8 @@ import { export type ModelExtensionContext = { priority: number; - resources?: WatchK8sResources; workloadKeys?: string[]; + resources?: WatchK8sResources; dataModelGetter?: TopologyDataModelGetter; dataModelDepicter?: TopologyDataModelDepicted; dataModelReconciler?: TopologyDataModelReconciler; diff --git a/frontend/packages/topology/src/hooks/useTopologyDataModelFactory.ts b/frontend/packages/topology/src/hooks/useTopologyDataModelFactory.ts deleted file mode 100644 index 0b62d468e56..00000000000 --- a/frontend/packages/topology/src/hooks/useTopologyDataModelFactory.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { useState, useEffect } from 'react'; -import { WatchK8sResourcesGeneric } from '@console/dynamic-plugin-sdk'; -import { CodeRef } from '@console/dynamic-plugin-sdk/src/types'; - -/** - * Resources type that can be: - * 1. Static WatchK8sResourcesGeneric (from dynamic plugin SDK) - * 2. CodeRef<() => Promise> (from dynamic plugin SDK, for dynamic resources) - */ -export type TopologyResourcesType = - | WatchK8sResourcesGeneric - | CodeRef<() => Promise>; - -/** - * Hook to resolve resources from TopologyDataModelFactory extension. - * Handles: - * - Static WatchK8sResourcesGeneric objects - * - Dynamic CodeRef<() => Promise> for plugins that need runtime fetching - * - * @param resources - Resources in any of the supported formats - * @returns Object with resolved resources (always in Generic format) - */ -export const useResolvedResources = ( - resources?: TopologyResourcesType, -): { resolved: WatchK8sResourcesGeneric | undefined; isGeneric: boolean } => { - const [resolvedResources, setResolvedResources] = useState( - undefined, - ); - const [loading, setLoading] = useState(true); - - useEffect(() => { - if (!resources) { - setResolvedResources(undefined); - setLoading(false); - return; - } - - if (typeof resources === 'function') { - // CodeRef format: CodeRef<() => Promise> - // which is a function that returns Promise<() => Promise> - setLoading(true); - const fetchResources = async () => { - try { - const codeRef = (resources as unknown) as CodeRef< - () => Promise - >; - const getResources = await codeRef(); - const result = await getResources(); - setResolvedResources(result); - } catch (error) { - // eslint-disable-next-line no-console - console.error('Failed to resolve dynamic topology resources:', error); - setResolvedResources(undefined); - } finally { - setLoading(false); - } - }; - fetchResources(); - } else { - // Static WatchK8sResourcesGeneric object - setResolvedResources(resources as WatchK8sResourcesGeneric); - setLoading(false); - } - }, [resources]); - - return loading - ? { resolved: undefined, isGeneric: false } - : { resolved: resolvedResources, isGeneric: true }; -}; From 6ec040b54c6bb682db47639f3697af8ae1180472 Mon Sep 17 00:00:00 2001 From: Leo6Leo <36619969+Leo6Leo@users.noreply.github.com> Date: Wed, 5 Nov 2025 15:53:06 -0500 Subject: [PATCH 10/16] fix: Refactor DataModelExtension to streamline resource conversion --- .../data-transforms/DataModelExtension.tsx | 86 ++++++++----------- 1 file changed, 36 insertions(+), 50 deletions(-) diff --git a/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx b/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx index 7e561f5b257..74c35504743 100644 --- a/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx +++ b/frontend/packages/topology/src/data-transforms/DataModelExtension.tsx @@ -2,7 +2,6 @@ import { useContext, useRef, useEffect, useMemo } from 'react'; import { WatchK8sResources, WatchK8sResourcesGeneric, - WatchK8sResource, TopologyDataModelFactory, ResolvedExtension, } from '@console/dynamic-plugin-sdk'; @@ -19,46 +18,6 @@ interface DataModelExtensionProps { pluginID: string; } -/** - * Converts a single resource from WatchK8sResourcesGeneric format to WatchK8sResource format. - * This handles the namespace injection and model reference resolution. - */ -const convertGenericResource = ( - namespace: string, - pluginID: string, - resourceKey: string, - model?: { group?: string; version?: string; kind: string }, - opts?: Partial, -): WatchK8sResource | null => { - if (!model) { - return { namespace, ...opts }; - } - - // If version is provided, use referenceForExtensionModel directly - if (model.version && model.group) { - const extensionReference = referenceForExtensionModel({ - group: model.group, - version: model.version, - kind: model.kind, - }); - return { namespace, kind: extensionReference, ...opts }; - } - - // Fall back to internal model reference resolution - const internalModel = modelForGroupKind(model.group, model.kind); - if (!internalModel) { - // CRD not found - log warning and skip - // eslint-disable-next-line no-console - console.warn( - `Plugin "${pluginID}": Could not find model (CRD) for group "${model.group}" and kind "${model.kind}" to determine version. Please add a required flag to the extension to suppress this warning. The resource "${resourceKey}" will not be loaded and ignored in the topology view for now.`, - ); - return null; - } - - const internalReference = referenceForModel(internalModel); - return { namespace, kind: internalReference, ...opts }; -}; - const DataModelExtension: React.FC = ({ dataModelFactory, pluginID }) => { const dataModelContext = useContext(ModelContext); const { @@ -82,16 +41,43 @@ const DataModelExtension: React.FC = ({ dataModelFactor const converted: WatchK8sResources = {}; Object.entries(genericResources).forEach(([key, resource]) => { - const flattenedResource = convertGenericResource( - dataModelContext.namespace, - pluginID, - key, - resource?.model, - resource?.opts, - ); - if (flattenedResource) { - converted[key] = flattenedResource; + const { model, opts } = resource; + + if (!model) { + // No model specified, just use opts with namespace + converted[key] = { namespace: dataModelContext.namespace, ...opts }; + return; + } + + // Convert model to kind reference + let kindReference: string | undefined; + + if (model.version && model.group) { + // Use referenceForExtensionModel for models with full GVK + kindReference = referenceForExtensionModel({ + group: model.group, + version: model.version, + kind: model.kind, + }); + } else { + // Fall back to internal model reference resolution + const internalModel = modelForGroupKind(model.group, model.kind); + if (!internalModel) { + // CRD not found - log warning and skip + // eslint-disable-next-line no-console + console.warn( + `Plugin "${pluginID}": Could not find model (CRD) for group "${model.group}" and kind "${model.kind}" to determine version. Please add a required flag to the extension to suppress this warning. The resource "${key}" will not be loaded and ignored in the topology view for now.`, + ); + return; + } + kindReference = referenceForModel(internalModel); } + + converted[key] = { + namespace: dataModelContext.namespace, + kind: kindReference, + ...opts, + }; }); return converted; From 726f09e0b4dbd6831052f62ad88f883c177fb0ab Mon Sep 17 00:00:00 2001 From: Leo6Leo <36619969+Leo6Leo@users.noreply.github.com> Date: Wed, 12 Nov 2025 16:09:34 -0500 Subject: [PATCH 11/16] Implement async resource resolution for dynamic model factories in DataModelProvider --- .../src/data-transforms/DataModelProvider.tsx | 57 ++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx b/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx index ea8a80f74f2..438734c68dc 100644 --- a/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx +++ b/frontend/packages/topology/src/data-transforms/DataModelProvider.tsx @@ -25,11 +25,64 @@ const DataModelProvider: React.FC = ({ namespace, childr DynamicTopologyDataModelFactory >(isDynamicTopologyDataModelFactory); + // State to track resolved factories (with async resources resolved) + const [resolvedFactories, setResolvedFactories] = React.useState< + | { + properties: any; + pluginID: string; + }[] + | null + >(null); + + // Resolve any async resources from factories + React.useEffect(() => { + if (!dynamicResolved || !dynamicModelFactories) { + setResolvedFactories(null); + return; + } + + const resolveFactories = async () => { + const resolved = await Promise.all( + dynamicModelFactories.map(async (factory) => { + const { resources, ...rest } = factory.properties; + + // Check if resources is a function (CodeRef that returns Promise) + if (typeof resources === 'function') { + try { + const resolvedResources = await resources(); + return { + properties: { ...rest, resources: resolvedResources }, + pluginID: factory.pluginID, + }; + } catch (error) { + // eslint-disable-next-line no-console + console.error( + `Failed to resolve resources for topology factory "${factory.properties.id}" from plugin "${factory.pluginID}":`, + error, + ); + return { + properties: { ...rest, resources: undefined }, + pluginID: factory.pluginID, + }; + } + } + + // Resources are already static, no resolution needed + return factory; + }), + ); + + setResolvedFactories(resolved); + }; + + resolveFactories(); + }, [dynamicModelFactories, dynamicResolved]); + return ( - {namespace && dynamicResolved && ( + {namespace && resolvedFactories && ( <> - {dynamicModelFactories.map((factory) => ( + {resolvedFactories.map((factory) => ( Date: Mon, 3 Nov 2025 23:29:08 -0500 Subject: [PATCH 12/16] CONSOLE-4840: Topology static extension cleanup --- .../CHANGELOG-core.md | 2 + .../src/extensions/topology-types.ts | 10 +- .../src/topology/knative-topology-utils.ts | 5 +- .../src/topology/topology-types.ts | 3 +- .../src/components/graph-view/Topology.tsx | 26 +-- .../src/components/page/TopologyView.tsx | 61 ++---- .../src/data-transforms/transform-utils.ts | 3 +- .../packages/topology/src/extensions/index.ts | 1 - .../topology/src/extensions/topology.ts | 57 ------ .../packages/topology/src/topology-types.ts | 180 +++--------------- 10 files changed, 70 insertions(+), 278 deletions(-) delete mode 100644 frontend/packages/topology/src/extensions/index.ts delete mode 100644 frontend/packages/topology/src/extensions/topology.ts diff --git a/frontend/packages/console-dynamic-plugin-sdk/CHANGELOG-core.md b/frontend/packages/console-dynamic-plugin-sdk/CHANGELOG-core.md index fe2c793065d..0f59f955c97 100644 --- a/frontend/packages/console-dynamic-plugin-sdk/CHANGELOG-core.md +++ b/frontend/packages/console-dynamic-plugin-sdk/CHANGELOG-core.md @@ -18,6 +18,7 @@ table in [Console dynamic plugins README](./README.md). - Begin alignment of plugin SDK types with `@openshift/dynamic-plugin-sdk` ([CONSOLE-3769], [#15509]) - Add optional `fetch` property to extension `console.dashboards/overview/health/url` ([CONSOLE-4796], [#15526]) - Add optional `infrastructure` parameter to `PrometheusHealthHandler` type ([CONSOLE-4796], [#15526]) +- Allow `K8sResourceKind` in `TopologyDataObject`, `TopologyResourcesObject`, and `OverviewItem` types ([CONSOLE-4840], [#15699]) ## 4.20.0-prerelease.1 - 2025-08-15 @@ -195,3 +196,4 @@ table in [Console dynamic plugins README](./README.md). [#15509]: https://github.com/openshift/console/pull/15509 [#15526]: https://github.com/openshift/console/pull/15526 [#15671]: https://github.com/openshift/console/pull/15671 +[#15699]: https://github.com/openshift/console/pull/15699 diff --git a/frontend/packages/console-dynamic-plugin-sdk/src/extensions/topology-types.ts b/frontend/packages/console-dynamic-plugin-sdk/src/extensions/topology-types.ts index b7b08397952..ff6a89dcec9 100644 --- a/frontend/packages/console-dynamic-plugin-sdk/src/extensions/topology-types.ts +++ b/frontend/packages/console-dynamic-plugin-sdk/src/extensions/topology-types.ts @@ -47,7 +47,7 @@ export interface OdcEdgeModel extends EdgeModel { resourceKind?: K8sResourceKindReference; } -export type TopologyResourcesObject = { [key: string]: K8sResourceCommon[] }; +export type TopologyResourcesObject = { [key: string]: K8sResourceKind[] }; export type TopologyDataResources = WatchK8sResults; @@ -101,9 +101,9 @@ export type TopologyDisplayOption = { value: boolean; }; -export type OverviewItem = { +export type OverviewItem = { obj: T; - hpas?: K8sResourceCommon[]; + hpas?: K8sResourceKind[]; isOperatorBackedService?: boolean; isMonitorable?: boolean; monitoringAlerts?: PrometheusAlert[]; @@ -133,9 +133,9 @@ export interface TopologyDataObject { name: string; type: string; resources: OverviewItem; - pods?: K8sResourceCommon[]; + pods?: K8sResourceKind[]; data: D; - resource: K8sResourceCommon | null; + resource: K8sResourceKind | null; groupResources?: OdcNodeModel[]; } diff --git a/frontend/packages/knative-plugin/src/topology/knative-topology-utils.ts b/frontend/packages/knative-plugin/src/topology/knative-topology-utils.ts index c24e4ab7731..5c515f6b51a 100644 --- a/frontend/packages/knative-plugin/src/topology/knative-topology-utils.ts +++ b/frontend/packages/knative-plugin/src/topology/knative-topology-utils.ts @@ -9,7 +9,8 @@ import { } from '@patternfly/react-topology/dist/esm/types'; import i18next from 'i18next'; import * as _ from 'lodash'; -import { WatchK8sResultsObject } from '@console/dynamic-plugin-sdk'; +import { WatchK8sResultsObject } from '@console/dynamic-plugin-sdk/src/extensions/console-types'; +import { OverviewItem } from '@console/dynamic-plugin-sdk/src/extensions/topology-types'; import { getImageForIconClass } from '@console/internal/components/catalog/catalog-item-icon'; import { DeploymentModel, PodModel, ServiceModel } from '@console/internal/models'; import { @@ -25,7 +26,7 @@ import { groupVersionFor, } from '@console/internal/module/k8s'; import { RootState } from '@console/internal/redux'; -import { getOwnedResources, OverviewItem } from '@console/shared'; +import { getOwnedResources } from '@console/shared'; import { NODE_WIDTH, NODE_HEIGHT, NODE_PADDING } from '@console/topology/src/const'; import { getTopologyGroupItems, diff --git a/frontend/packages/knative-plugin/src/topology/topology-types.ts b/frontend/packages/knative-plugin/src/topology/topology-types.ts index dfc15035a42..d49cf07341e 100644 --- a/frontend/packages/knative-plugin/src/topology/topology-types.ts +++ b/frontend/packages/knative-plugin/src/topology/topology-types.ts @@ -1,5 +1,6 @@ +import { PodControllerOverviewItem } from '@console/dynamic-plugin-sdk/src/extensions/console-types'; +import { OverviewItem } from '@console/dynamic-plugin-sdk/src/extensions/topology-types'; import { K8sResourceKind } from '@console/internal/module/k8s'; -import { OverviewItem, PodControllerOverviewItem } from '@console/shared/src'; import { TopologyDataObject } from '@console/topology/src/topology-types'; import { KnativeItem } from '../utils/get-knative-resources'; diff --git a/frontend/packages/topology/src/components/graph-view/Topology.tsx b/frontend/packages/topology/src/components/graph-view/Topology.tsx index 458260d54ec..631c7be1394 100644 --- a/frontend/packages/topology/src/components/graph-view/Topology.tsx +++ b/frontend/packages/topology/src/components/graph-view/Topology.tsx @@ -23,11 +23,11 @@ import { import * as _ from 'lodash'; import { action } from 'mobx'; import { connect } from 'react-redux'; +import { useResolvedExtensions } from '@console/dynamic-plugin-sdk/src/api/useResolvedExtensions'; import { - useResolvedExtensions, - isTopologyComponentFactory as isDynamicTopologyComponentFactory, - TopologyComponentFactory as DynamicTopologyComponentFactory, -} from '@console/dynamic-plugin-sdk'; + isTopologyComponentFactory, + TopologyComponentFactory, +} from '@console/dynamic-plugin-sdk/src/extensions/topology'; import { RootState } from '@console/internal/redux'; import { useQueryParams, @@ -37,7 +37,6 @@ import { import { withFallback, ErrorBoundaryFallbackPage } from '@console/shared/src/components/error'; import { TOPOLOGY_LAYOUT_CONFIG_STORAGE_KEY, TOPOLOGY_LAYOUT_LOCAL_STORAGE_KEY } from '../../const'; import { odcElementFactory } from '../../elements'; -import { isTopologyComponentFactory, TopologyComponentFactory } from '../../extensions/topology'; import { getTopologyGraphModel, setTopologyGraphModel } from '../../redux/action'; import { SHOW_GROUPING_HINT_EVENT, ShowGroupingHintEventListener } from '../../topology-types'; import { componentFactory } from './components'; @@ -148,12 +147,9 @@ const Topology: React.FC< const storedLayoutApplied = React.useRef(false); const queryParams = useQueryParams(); const selectedId = queryParams.get('selectId'); - const [componentFactoryExtensions, isStaticResolved] = useResolvedExtensions< + const [componentFactoryExtensions, extensionsResolved] = useResolvedExtensions< TopologyComponentFactory >(isTopologyComponentFactory); - const [dynamicComponentFactoryExtensions, isDynamicResolved] = useResolvedExtensions< - DynamicTopologyComponentFactory - >(isDynamicTopologyComponentFactory); const createVisualization = React.useCallback(() => { const storedLayout = topologyLayoutDataJson?.[namespace]; @@ -296,12 +292,12 @@ const Topology: React.FC< }, [model, visualization, visualizationReady]); React.useEffect(() => { - if (!isStaticResolved || !isDynamicResolved) { + if (!extensionsResolved) { return; } visualization.registerComponentFactory(componentFactory); - [...componentFactoryExtensions, ...dynamicComponentFactoryExtensions].forEach((factory) => { + componentFactoryExtensions.forEach((factory) => { visualization.registerComponentFactory(factory.properties.getFactory); }); @@ -312,13 +308,7 @@ const Topology: React.FC< }, ); setVisualizationReady(true); - }, [ - visualization, - isStaticResolved, - isDynamicResolved, - componentFactoryExtensions, - dynamicComponentFactoryExtensions, - ]); + }, [visualization, extensionsResolved, componentFactoryExtensions]); React.useEffect(() => { if (!applicationRef.current) { diff --git a/frontend/packages/topology/src/components/page/TopologyView.tsx b/frontend/packages/topology/src/components/page/TopologyView.tsx index ccb6e1d2743..8397b4d12a8 100644 --- a/frontend/packages/topology/src/components/page/TopologyView.tsx +++ b/frontend/packages/topology/src/components/page/TopologyView.tsx @@ -16,17 +16,17 @@ import { FileUploadContext, } from '@console/app/src/components/file-upload/file-upload-context'; import { useAddToProjectAccess } from '@console/dev-console/src/utils/useAddToProjectAccess'; +import { useResolvedExtensions } from '@console/dynamic-plugin-sdk/src/api/useResolvedExtensions'; import { - useResolvedExtensions, isTopologyCreateConnector, - isTopologyDecoratorProvider as isDynamicTopologyDecoratorProvider, - isTopologyDisplayFilters as isDynamicTopologyDisplayFilters, + isTopologyDecoratorProvider, + isTopologyDisplayFilters, TopologyCreateConnector, - TopologyDecoratorProvider as DynamicTopologyDecoratorProvider, - TopologyDisplayFilters as DynamicTopologyDisplayFilters, + TopologyDecoratorProvider, + TopologyDisplayFilters, TopologyRelationshipProvider, isTopologyRelationshipProvider, -} from '@console/dynamic-plugin-sdk'; +} from '@console/dynamic-plugin-sdk/src/extensions/topology'; import { selectOverviewDetailsTab } from '@console/internal/actions/ui'; import { getQueryArgument, @@ -40,12 +40,6 @@ import { useDeepCompareMemoize, useQueryParams } from '@console/shared'; import { useTelemetry } from '@console/shared/src/hooks/useTelemetry'; import { LAST_TOPOLOGY_OVERVIEW_OPEN_STORAGE_KEY } from '../../const'; import { updateModelFromFilters } from '../../data-transforms/updateModelFromFilters'; -import { - isTopologyDecoratorProvider, - isTopologyDisplayFilters, - TopologyDecoratorProvider, - TopologyDisplayFilters, -} from '../../extensions/topology'; import { getTopologySearchQuery, TOPOLOGY_LABELS_FILTER_KEY, @@ -135,24 +129,16 @@ export const ConnectedTopologyView: React.FC = ({ [fireTelemetryEvent], ); const appliedFilters = useAppliedDisplayFilters(); + const [displayFilterExtensions, displayFilterExtensionsResolved] = useResolvedExtensions< TopologyDisplayFilters >(isTopologyDisplayFilters); - - const [extensionDecorators, extensionDecoratorsResolved] = useResolvedExtensions< - TopologyDecoratorProvider - >(isTopologyDecoratorProvider); - - const [ - dynamicDisplayFilterExtensions, - dynamicDisplayFilterExtensionsResolved, - ] = useResolvedExtensions(isDynamicTopologyDisplayFilters); const [createConnectors, createConnectorsResolved] = useResolvedExtensions< TopologyCreateConnector >(isTopologyCreateConnector); - const [dynamicExtensionDecorators, dynamicExtensionDecoratorsResolved] = useResolvedExtensions< - DynamicTopologyDecoratorProvider - >(isDynamicTopologyDecoratorProvider); + const [extensionDecorators, extensionDecoratorsResolved] = useResolvedExtensions< + TopologyDecoratorProvider + >(isTopologyDecoratorProvider); const [relationshipProvider] = useResolvedExtensions( isTopologyRelationshipProvider, ); @@ -218,8 +204,8 @@ export const ConnectedTopologyView: React.FC = ({ }, [visualization, graphData]); React.useEffect(() => { - if (extensionDecoratorsResolved && dynamicExtensionDecoratorsResolved) { - const allDecorators = [...extensionDecorators, ...dynamicExtensionDecorators].reduce( + if (extensionDecoratorsResolved) { + const allDecorators = extensionDecorators.reduce( (acc, extensionDecorator) => { const decorator: TopologyDecorator = extensionDecorator.properties; if (!acc[decorator.quadrant]) { @@ -240,17 +226,12 @@ export const ConnectedTopologyView: React.FC = ({ ); setTopologyDecorators(allDecorators); } - }, [ - dynamicExtensionDecorators, - dynamicExtensionDecoratorsResolved, - extensionDecorators, - extensionDecoratorsResolved, - ]); + }, [extensionDecorators, extensionDecoratorsResolved]); React.useEffect(() => { - if (displayFilterExtensionsResolved && dynamicDisplayFilterExtensionsResolved) { + if (displayFilterExtensionsResolved) { const updateFilters = [...filters]; - [...displayFilterExtensions, ...dynamicDisplayFilterExtensions].forEach((extension) => { + displayFilterExtensions.forEach((extension) => { const extFilters = extension.properties.getTopologyFilters(); extFilters?.forEach((filter) => { if (!updateFilters.find((f) => f.id === filter.id)) { @@ -266,12 +247,7 @@ export const ConnectedTopologyView: React.FC = ({ } // Only update on extension changes // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ - displayFilterExtensionsResolved, - dynamicDisplayFilterExtensionsResolved, - displayFilterExtensions, - dynamicDisplayFilterExtensions, - ]); + }, [displayFilterExtensionsResolved, displayFilterExtensions]); React.useEffect(() => { if (filtersLoaded) { @@ -279,9 +255,7 @@ export const ConnectedTopologyView: React.FC = ({ model, filters, application, - [...displayFilterExtensions, ...dynamicDisplayFilterExtensions].map( - (extension) => extension.properties.applyDisplayOptions, - ), + displayFilterExtensions.map((extension) => extension.properties.applyDisplayOptions), onSupportedFiltersChange, onSupportedKindsChange, ); @@ -296,7 +270,6 @@ export const ConnectedTopologyView: React.FC = ({ onSupportedFiltersChange, onSupportedKindsChange, displayFilterExtensions, - dynamicDisplayFilterExtensions, ]); React.useEffect(() => { diff --git a/frontend/packages/topology/src/data-transforms/transform-utils.ts b/frontend/packages/topology/src/data-transforms/transform-utils.ts index deb1f16c956..3e4ae4323db 100644 --- a/frontend/packages/topology/src/data-transforms/transform-utils.ts +++ b/frontend/packages/topology/src/data-transforms/transform-utils.ts @@ -12,6 +12,7 @@ import { GetTopologyNodeItem, GetWorkloadResources, MergeGroup, + OverviewItem, } from '@console/dynamic-plugin-sdk/src/extensions/topology-types'; import { getImageForIconClass } from '@console/internal/components/catalog/catalog-item-icon'; import { Alerts } from '@console/internal/components/monitoring/types'; @@ -28,7 +29,7 @@ import { TYPE_EVENT_SOURCE_KAFKA, TYPE_KNATIVE_REVISION, } from '@console/knative-plugin/src/topology/const'; -import { isKnativeServing, OverviewItem } from '@console/shared'; +import { isKnativeServing } from '@console/shared/src/utils/pod-utils'; import { returnIfValidURL } from '@console/shared/src/utils/utils'; import { TYPE_APPLICATION_GROUP, diff --git a/frontend/packages/topology/src/extensions/index.ts b/frontend/packages/topology/src/extensions/index.ts deleted file mode 100644 index fb73dc20c45..00000000000 --- a/frontend/packages/topology/src/extensions/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './topology'; diff --git a/frontend/packages/topology/src/extensions/topology.ts b/frontend/packages/topology/src/extensions/topology.ts deleted file mode 100644 index 7e4342136f0..00000000000 --- a/frontend/packages/topology/src/extensions/topology.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { TopologyQuadrant } from '@patternfly/react-topology'; -import { CodeRef } from '@console/dynamic-plugin-sdk/src/types'; -import { Extension } from '@console/plugin-sdk/src/typings/base'; -import { - TopologyApplyDisplayOptions, - TopologyDisplayOption, - ViewComponentFactory, - TopologyDecoratorGetter, -} from '../topology-types'; - -namespace ExtensionProperties { - export interface TopologyComponentFactory { - /** Getter for a ViewComponentFactory */ - getFactory: CodeRef; - } - - export interface TopologyDisplayFilters { - // Getter for topology filters specific to the extension - getTopologyFilters: CodeRef<() => TopologyDisplayOption[]>; - // Function to apply filters to the model - applyDisplayOptions: CodeRef; - } - - export interface TopologyDecoratorProvider { - id: string; - priority: number; - quadrant: TopologyQuadrant; - decorator: CodeRef; - } -} - -export interface TopologyComponentFactory - extends Extension { - type: 'Topology/ComponentFactory'; -} - -export interface TopologyDisplayFilters - extends Extension { - type: 'Topology/DisplayFilters'; -} - -export interface TopologyDecoratorProvider - extends Extension { - type: 'Topology/Decorator'; -} - -export const isTopologyComponentFactory = (e: Extension): e is TopologyComponentFactory => { - return e.type === 'Topology/ComponentFactory'; -}; - -export const isTopologyDisplayFilters = (e: Extension): e is TopologyDisplayFilters => { - return e.type === 'Topology/DisplayFilters'; -}; - -export const isTopologyDecoratorProvider = (e: Extension): e is TopologyDecoratorProvider => { - return e.type === 'Topology/Decorator'; -}; diff --git a/frontend/packages/topology/src/topology-types.ts b/frontend/packages/topology/src/topology-types.ts index 99edfdd5029..06aa4f1a59f 100644 --- a/frontend/packages/topology/src/topology-types.ts +++ b/frontend/packages/topology/src/topology-types.ts @@ -1,149 +1,31 @@ -import * as React from 'react'; -import { - Node, - Model, - EdgeModel, - NodeModel, - EventListener, - ModelKind, - GraphElement, - TopologyQuadrant, -} from '@patternfly/react-topology'; -import { WatchK8sResults } from '@console/dynamic-plugin-sdk'; -import { CreateConnectionGetter } from '@console/dynamic-plugin-sdk/src/extensions/topology-types'; -import { K8sResourceKind, K8sResourceKindReference } from '@console/internal/module/k8s'; -import { ExtPodKind, OverviewItem } from '@console/shared'; - -export type Point = [number, number]; - -export interface OdcNodeModel extends NodeModel { - resource?: K8sResourceKind; - resourceKind?: K8sResourceKindReference; -} - -export interface OdcEdgeModel extends EdgeModel { - resource?: K8sResourceKind; - resourceKind?: K8sResourceKindReference; -} - -export type TopologyResourcesObject = { [key: string]: K8sResourceKind[] }; - -export type TopologyDataResources = WatchK8sResults; - -export type TopologyDataModelGetter = ( - namespace: string, - resources: TopologyDataResources, - workloads: K8sResourceKind[], -) => Promise; - -export enum TopologyViewType { - graph = 'graph', - list = 'list', -} -export type ViewComponentFactory = ( - kind: ModelKind, - type: string, - view?: TopologyViewType, -) => React.ComponentType<{ element: GraphElement }> | undefined; - -export type TopologyDataModelDepicted = (resource: K8sResourceKind, model: Model) => boolean; - -export type TopologyDataModelReconciler = (model: Model, resources: TopologyDataResources) => void; - -export enum TopologyDisplayFilterType { - show = 'show', - expand = 'expand', - kind = 'kind', -} - -export type TopologyDisplayOption = { - type: TopologyDisplayFilterType; - id: string; - label?: string; - labelKey?: string; - priority: number; - value: boolean; -}; - -export type DisplayFilters = TopologyDisplayOption[]; - -// Applies the filters on the model and returns the ids of filters that were relevant -export type TopologyApplyDisplayOptions = (model: Model, filters: DisplayFilters) => string[]; - -export type TopologyDecoratorGetter = ( - element: Node, - radius: number, - centerX: number, - centerY: number, -) => React.ReactElement; - -export type TopologyDecorator = { - id: string; - priority: number; - quadrant: TopologyQuadrant; - decorator: TopologyDecoratorGetter; -}; - -export interface TopologyDataObject { - id: string; - name: string; - type: string; - resources: OverviewItem; - pods?: ExtPodKind[]; - data: D; - resource: K8sResourceKind | null; - groupResources?: OdcNodeModel[]; -} - -export interface TopologyApplicationObject { - id: string; - name: string; - resources: OdcNodeModel[]; -} - -export interface WorkloadData { - editURL?: string; - vcsURI?: string; - vcsRef?: string; - builderImage?: string; - kind?: string; - isKnativeResource?: boolean; -} - -export type TrafficData = { - nodes: KialiNode[]; - edges: KialiEdge[]; -}; - -export type KialiNode = { - data: { - id: string; - nodeType: string; - namespace: string; - workload: string; - app: string; - version?: string; - destServices?: { [key: string]: any }[]; - traffic?: { [key: string]: any }[]; - }; -}; - -export type KialiEdge = { - data: { - id: string; - source: string; - target: string; - traffic: { [key: string]: any }; - }; -}; - -export type GraphData = { - namespace: string; - createResourceAccess: string[]; - eventSourceEnabled: boolean; - createConnectorExtensions?: CreateConnectionGetter[]; - decorators?: { [key: string]: TopologyDecorator[] }; -}; - -export const SHOW_GROUPING_HINT_EVENT = 'show-regroup-hint'; -export type ShowGroupingHintEventListener = EventListener<[Node, string]>; +// re-export for convenience +export type { + Point, + OdcNodeModel, + OdcEdgeModel, + TopologyResourcesObject, + TopologyDataResources, + TopologyDataModelGetter, + ViewComponentFactory, + TopologyDataModelDepicted, + TopologyDataModelReconciler, + TopologyDisplayOption, + TopologyApplyDisplayOptions, + DisplayFilters, + TopologyDecoratorGetter, + TopologyDecorator, + TopologyDataObject, + TopologyApplicationObject, + WorkloadData, + TrafficData, + KialiNode, + KialiEdge, + GraphData, + ShowGroupingHintEventListener, +} from '@console/dynamic-plugin-sdk/src/extensions/topology-types'; + +export { + TopologyViewType, + TopologyDisplayFilterType, + SHOW_GROUPING_HINT_EVENT, +} from '@console/dynamic-plugin-sdk/src/extensions/topology-types'; From 9f378b8eca998f7893f93cacadcd811894e8aef2 Mon Sep 17 00:00:00 2001 From: logonoff Date: Mon, 17 Nov 2025 23:28:11 -0500 Subject: [PATCH 13/16] CONSOLE-4840: Set cycle threshold to 0 --- frontend/webpack.config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/webpack.config.ts b/frontend/webpack.config.ts index 5bef0149b9a..ef735a5876c 100644 --- a/frontend/webpack.config.ts +++ b/frontend/webpack.config.ts @@ -340,7 +340,6 @@ const config: Configuration = { if (CHECK_CYCLES === 'true') { new CircularDependencyPreset({ exclude: /node_modules|public\/dist|\.(gql|html)$/, - thresholds: { totalCycles: 14 }, // TODO(CONSOLE-4806): Set threshold to 0 reportFile: '.webpack-cycles', }).apply(config.plugins); } From 599587a1e10611579d40b23dcd2fc9ace821bc19 Mon Sep 17 00:00:00 2001 From: logonoff Date: Mon, 17 Nov 2025 23:34:58 -0500 Subject: [PATCH 14/16] CONSOLE-3769: Make plugin info status lowercase to align with openshift/dynamic-plugin-sdl --- .../console-operator/ConsoleOperatorConfig.tsx | 6 +++--- .../ConsolePluginStatusDetail.tsx | 2 +- .../DynamicPluginsPopover.tsx | 4 ++-- .../dynamic-plugins-health-resource/status.ts | 6 +++--- .../src/hooks/useCSPViolationDetector.tsx | 2 +- .../__tests__/plugin-dependencies.spec.ts | 6 +++--- .../src/runtime/plugin-dependencies.ts | 4 ++-- .../src/__tests__/store.spec.ts | 10 +++++----- .../console-plugin-sdk/src/api/usePluginInfo.ts | 2 +- .../packages/console-plugin-sdk/src/store.ts | 16 ++++++++-------- .../public/components/notification-drawer.tsx | 2 +- 11 files changed, 30 insertions(+), 30 deletions(-) diff --git a/frontend/packages/console-app/src/components/console-operator/ConsoleOperatorConfig.tsx b/frontend/packages/console-app/src/components/console-operator/ConsoleOperatorConfig.tsx index 7f9d945327f..a1adb5629eb 100644 --- a/frontend/packages/console-app/src/components/console-operator/ConsoleOperatorConfig.tsx +++ b/frontend/packages/console-app/src/components/console-operator/ConsoleOperatorConfig.tsx @@ -94,7 +94,7 @@ export const useConsoleOperatorConfigData = () => { export const ConsolePluginStatus: React.FC = ({ status, errorMessage, -}) => ; +}) => ; export const ConsolePluginEnabledStatus: React.FC = ({ pluginName, @@ -362,9 +362,9 @@ const PluginsPage: React.FC = (props) => { enabled, status: notLoadedPluginInfo?.status, errorMessage: - notLoadedPluginInfo?.status === 'Failed' ? notLoadedPluginInfo?.errorMessage : undefined, + notLoadedPluginInfo?.status === 'failed' ? notLoadedPluginInfo?.errorMessage : undefined, errorCause: - notLoadedPluginInfo?.status === 'Failed' + notLoadedPluginInfo?.status === 'failed' ? notLoadedPluginInfo?.errorCause?.toString() : undefined, }; diff --git a/frontend/packages/console-app/src/components/console-operator/ConsolePluginStatusDetail.tsx b/frontend/packages/console-app/src/components/console-operator/ConsolePluginStatusDetail.tsx index 97753a86ff4..b296fba47ff 100644 --- a/frontend/packages/console-app/src/components/console-operator/ConsolePluginStatusDetail.tsx +++ b/frontend/packages/console-app/src/components/console-operator/ConsolePluginStatusDetail.tsx @@ -22,7 +22,7 @@ const ConsolePluginStatusDetail: React.FC = ({ obj }) return pluginInfo ? ( ) : ( <>{DASH} diff --git a/frontend/packages/console-app/src/components/dashboards-page/dynamic-plugins-health-resource/DynamicPluginsPopover.tsx b/frontend/packages/console-app/src/components/dashboards-page/dynamic-plugins-health-resource/DynamicPluginsPopover.tsx index 5deca91790c..7512e3181bd 100644 --- a/frontend/packages/console-app/src/components/dashboards-page/dynamic-plugins-health-resource/DynamicPluginsPopover.tsx +++ b/frontend/packages/console-app/src/components/dashboards-page/dynamic-plugins-health-resource/DynamicPluginsPopover.tsx @@ -20,8 +20,8 @@ const DynamicPluginsPopover: React.FC = ({ consolePl UI.get('pluginCSPViolations'), ); const notLoadedDynamicPluginInfo = pluginInfoEntries.filter(isNotLoadedDynamicPluginInfo); - const failedPlugins = notLoadedDynamicPluginInfo.filter((plugin) => plugin.status === 'Failed'); - const pendingPlugins = notLoadedDynamicPluginInfo.filter((plugin) => plugin.status === 'Pending'); + const failedPlugins = notLoadedDynamicPluginInfo.filter((plugin) => plugin.status === 'failed'); + const pendingPlugins = notLoadedDynamicPluginInfo.filter((plugin) => plugin.status === 'pending'); const loadedPlugins = pluginInfoEntries.filter(isLoadedDynamicPluginInfo); const loadedPluginsWithCSPViolations = loadedPlugins.filter( (plugin) => cspViolations[plugin.metadata.name] ?? false, diff --git a/frontend/packages/console-app/src/components/dashboards-page/dynamic-plugins-health-resource/status.ts b/frontend/packages/console-app/src/components/dashboards-page/dynamic-plugins-health-resource/status.ts index 2661e8bad20..3179cbd5bf5 100644 --- a/frontend/packages/console-app/src/components/dashboards-page/dynamic-plugins-health-resource/status.ts +++ b/frontend/packages/console-app/src/components/dashboards-page/dynamic-plugins-health-resource/status.ts @@ -3,13 +3,13 @@ import { pluginStore } from '@console/internal/plugins'; export const getDynamicPluginHealthState = (): SubsystemHealth => { const dynamicPluginInfo = pluginStore.getPluginInfo(); - if (dynamicPluginInfo.some((plugin) => plugin.status === 'Failed')) { + if (dynamicPluginInfo.some((plugin) => plugin.status === 'failed')) { return { state: HealthState.ERROR }; } - if (dynamicPluginInfo.some((plugin) => plugin.status === 'Pending')) { + if (dynamicPluginInfo.some((plugin) => plugin.status === 'pending')) { return { state: HealthState.PROGRESS }; } - if (dynamicPluginInfo.every((plugin) => plugin.status === 'Loaded')) { + if (dynamicPluginInfo.every((plugin) => plugin.status === 'loaded')) { return { state: HealthState.OK }; } return { state: HealthState.UNKNOWN }; diff --git a/frontend/packages/console-app/src/hooks/useCSPViolationDetector.tsx b/frontend/packages/console-app/src/hooks/useCSPViolationDetector.tsx index e3d05edf6e0..7f8800caa0e 100644 --- a/frontend/packages/console-app/src/hooks/useCSPViolationDetector.tsx +++ b/frontend/packages/console-app/src/hooks/useCSPViolationDetector.tsx @@ -110,7 +110,7 @@ export const useCSPViolationDetector = () => { ); const validPlugin = !!pluginInfo; - const pluginIsLoaded = validPlugin && pluginInfo.status === 'Loaded'; + const pluginIsLoaded = validPlugin && pluginInfo.status === 'loaded'; // eslint-disable-next-line no-console console.warn( diff --git a/frontend/packages/console-dynamic-plugin-sdk/src/runtime/__tests__/plugin-dependencies.spec.ts b/frontend/packages/console-dynamic-plugin-sdk/src/runtime/__tests__/plugin-dependencies.spec.ts index 31fa9ecfd98..9739f59470d 100644 --- a/frontend/packages/console-dynamic-plugin-sdk/src/runtime/__tests__/plugin-dependencies.spec.ts +++ b/frontend/packages/console-dynamic-plugin-sdk/src/runtime/__tests__/plugin-dependencies.spec.ts @@ -28,7 +28,7 @@ describe('resolvePluginDependencies', () => { const getLoadedDynamicPluginInfo = ( manifest: StandardConsolePluginManifest, ): LoadedDynamicPluginInfo => ({ - status: 'Loaded', + status: 'loaded', pluginID: getPluginID(manifest), metadata: _.omit(manifest, ['extensions', 'loadScripts', 'registrationMethod']), enabled: true, @@ -37,14 +37,14 @@ describe('resolvePluginDependencies', () => { const getPendingDynamicPluginInfo = ( manifest: StandardConsolePluginManifest, ): NotLoadedDynamicPluginInfo => ({ - status: 'Pending', + status: 'pending', pluginName: manifest.name, }); const getFailedDynamicPluginInfo = ( manifest: StandardConsolePluginManifest, ): NotLoadedDynamicPluginInfo => ({ - status: 'Failed', + status: 'failed', pluginName: manifest.name, errorMessage: `Test error message for plugin ${manifest.name}`, }); diff --git a/frontend/packages/console-dynamic-plugin-sdk/src/runtime/plugin-dependencies.ts b/frontend/packages/console-dynamic-plugin-sdk/src/runtime/plugin-dependencies.ts index 6743081e075..6fe3d045550 100644 --- a/frontend/packages/console-dynamic-plugin-sdk/src/runtime/plugin-dependencies.ts +++ b/frontend/packages/console-dynamic-plugin-sdk/src/runtime/plugin-dependencies.ts @@ -119,14 +119,14 @@ export const resolvePluginDependencies = ( const unsubListener = subscribeToDynamicPlugins((entries) => { const loadedPlugins = entries.reduce>((acc, e) => { - if (e.status === 'Loaded' && preloadPluginNames.includes(e.metadata.name)) { + if (e.status === 'loaded' && preloadPluginNames.includes(e.metadata.name)) { acc[e.metadata.name] = e.metadata.version; } return acc; }, {}); const failedPluginNames = entries.reduce((acc, e) => { - if (e.status === 'Failed' && preloadPluginNames.includes(e.pluginName)) { + if (e.status === 'failed' && preloadPluginNames.includes(e.pluginName)) { acc.push(e.pluginName); } return acc; diff --git a/frontend/packages/console-plugin-sdk/src/__tests__/store.spec.ts b/frontend/packages/console-plugin-sdk/src/__tests__/store.spec.ts index 78acd38f276..16472b18cae 100644 --- a/frontend/packages/console-plugin-sdk/src/__tests__/store.spec.ts +++ b/frontend/packages/console-plugin-sdk/src/__tests__/store.spec.ts @@ -582,7 +582,7 @@ describe('PluginStore', () => { expect(store.getExtensions()).toEqual([]); expect(store.getPluginInfo()).toEqual([ { - status: 'Loaded', + status: 'loaded', pluginID: 'Test@1.2.3', metadata: _.omit(manifest, ['extensions', 'loadScripts', 'registrationMethod']), enabled: false, @@ -967,7 +967,7 @@ describe('PluginStore', () => { expect(store.getPluginInfo()).toEqual([ { - status: 'Loaded', + status: 'loaded', pluginID: 'TestA@1.2.3', metadata: _.omit(manifest, ['extensions', 'loadScripts', 'registrationMethod']), enabled: false, @@ -982,7 +982,7 @@ describe('PluginStore', () => { expect(store.getPluginInfo()).toEqual([ { - status: 'Loaded', + status: 'loaded', pluginID: 'TestA@1.2.3', metadata: _.omit(manifest, ['extensions', 'loadScripts', 'registrationMethod']), enabled: true, @@ -995,7 +995,7 @@ describe('PluginStore', () => { expect(store.getPluginInfo()).toEqual([ { - status: 'Loaded', + status: 'loaded', pluginID: 'TestA@1.2.3', metadata: _.omit(manifest, ['extensions', 'loadScripts', 'registrationMethod']), enabled: true, @@ -1010,7 +1010,7 @@ describe('PluginStore', () => { expect(store.getPluginInfo()).toEqual([ { - status: 'Loaded', + status: 'loaded', pluginID: 'TestA@1.2.3', metadata: _.omit(manifest, ['extensions', 'loadScripts', 'registrationMethod']), enabled: true, diff --git a/frontend/packages/console-plugin-sdk/src/api/usePluginInfo.ts b/frontend/packages/console-plugin-sdk/src/api/usePluginInfo.ts index bbb218ba592..1931e5d968b 100644 --- a/frontend/packages/console-plugin-sdk/src/api/usePluginInfo.ts +++ b/frontend/packages/console-plugin-sdk/src/api/usePluginInfo.ts @@ -34,7 +34,7 @@ export const usePluginInfo = (): [DynamicPluginInfo[], boolean] => { if (unsubscribeRef.current === null) { unsubscribeRef.current = subscribeToDynamicPlugins((pluginInfoEntries) => { pluginInfoEntriesRef.current = pluginInfoEntries; - allPluginsProcessedRef.current = pluginInfoEntries.every((i) => i.status !== 'Pending'); + allPluginsProcessedRef.current = pluginInfoEntries.every((i) => i.status !== 'pending'); isMountedRef.current && forceRender(); }); } diff --git a/frontend/packages/console-plugin-sdk/src/store.ts b/frontend/packages/console-plugin-sdk/src/store.ts index 7814e16c558..8ad084895d0 100644 --- a/frontend/packages/console-plugin-sdk/src/store.ts +++ b/frontend/packages/console-plugin-sdk/src/store.ts @@ -33,11 +33,11 @@ export const getGatingFlagNames = (extensions: Extension[]): string[] => ]); export const isLoadedDynamicPluginInfo = (i: DynamicPluginInfo): i is LoadedDynamicPluginInfo => - i?.status === 'Loaded'; + i?.status === 'loaded'; export const isNotLoadedDynamicPluginInfo = ( i: DynamicPluginInfo, -): i is NotLoadedDynamicPluginInfo => i.status === 'Failed' || i.status === 'Pending'; +): i is NotLoadedDynamicPluginInfo => i.status === 'failed' || i.status === 'pending'; /** * Provides access to Console plugins and their extensions. @@ -245,7 +245,7 @@ export class PluginStore { const loadedPluginEntries = Array.from(this.loadedDynamicPlugins.entries()).reduce( (acc, [pluginID, plugin]) => { acc.push({ - status: 'Loaded', + status: 'loaded', pluginID, metadata: _.omit(plugin.manifest, ['extensions', 'loadScripts', 'registrationMethod']), enabled: plugin.enabled, @@ -258,7 +258,7 @@ export class PluginStore { const failedPluginEntries = Array.from(this.failedDynamicPlugins.entries()).reduce( (acc, [pluginName, plugin]) => { acc.push({ - status: 'Failed', + status: 'failed', pluginName, errorMessage: plugin.errorMessage, errorCause: plugin.errorCause, @@ -275,7 +275,7 @@ export class PluginStore { ) .reduce((acc, pluginName) => { acc.push({ - status: 'Pending', + status: 'pending', pluginName, }); return acc; @@ -327,7 +327,7 @@ type FailedDynamicPlugin = { }; export type LoadedDynamicPluginInfo = { - status: 'Loaded'; + status: 'loaded'; pluginID: string; metadata: DynamicPluginMetadata; enabled: boolean; @@ -335,11 +335,11 @@ export type LoadedDynamicPluginInfo = { export type NotLoadedDynamicPluginInfo = | { - status: 'Pending'; + status: 'pending'; pluginName: string; } | { - status: 'Failed'; + status: 'failed'; pluginName: string; errorMessage: string; errorCause?: unknown; diff --git a/frontend/public/components/notification-drawer.tsx b/frontend/public/components/notification-drawer.tsx index 9dfb603fc19..862b82084ec 100644 --- a/frontend/public/components/notification-drawer.tsx +++ b/frontend/public/components/notification-drawer.tsx @@ -164,7 +164,7 @@ const getUpdateNotificationEntries = ( const failedPlugins = pluginInfoEntries .filter(isNotLoadedDynamicPluginInfo) - .filter((plugin) => plugin.status === 'Failed'); + .filter((plugin) => plugin.status === 'failed'); if (!_.isEmpty(updateData)) { entries.push( From 777b56bb95ca38b23e8f6b6db1ba8d6898655989 Mon Sep 17 00:00:00 2001 From: logonoff Date: Mon, 17 Nov 2025 23:35:54 -0500 Subject: [PATCH 15/16] RHSTOR-6927: Remove LSO i18n namespace --- frontend/public/i18n.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/public/i18n.js b/frontend/public/i18n.js index 9cece429003..e5a4a9e1663 100644 --- a/frontend/public/i18n.js +++ b/frontend/public/i18n.js @@ -66,7 +66,6 @@ export const init = () => { 'helm-plugin', 'insights-plugin', 'knative-plugin', - 'lso-plugin', 'metal3-plugin', 'notification-drawer', 'olm', From 95a28f4c4f0b76278338afb98f8029176e17897a Mon Sep 17 00:00:00 2001 From: logonoff Date: Mon, 17 Nov 2025 23:49:05 -0500 Subject: [PATCH 16/16] CONSOLE-4840: Remove all plugin entry points --- frontend/packages/console-app/package.json | 1 - frontend/packages/console-app/src/plugin.ts | 2 - .../codegen/__tests__/active-plugins.spec.ts | 18 ++++---- .../codegen/__tests__/plugin-resolver.spec.ts | 41 ++++--------------- .../src/codegen/active-plugins.ts | 11 +---- .../src/codegen/plugin-resolver.ts | 8 +--- .../console-plugin-sdk/src/typings/base.ts | 41 ------------------- .../console-telemetry-plugin/package.json | 1 - .../console-telemetry-plugin/src/plugin.ts | 3 -- .../packages/container-security/package.json | 1 - .../packages/container-security/src/plugin.ts | 2 - frontend/packages/dev-console/package.json | 1 - frontend/packages/dev-console/src/plugin.ts | 2 - frontend/packages/helm-plugin/package.json | 1 - frontend/packages/helm-plugin/src/plugin.ts | 3 -- .../packages/insights-plugin/package.json | 1 - .../packages/insights-plugin/src/plugin.ts | 2 - frontend/packages/knative-plugin/package.json | 1 - .../packages/knative-plugin/src/plugin.ts | 2 - frontend/packages/metal3-plugin/package.json | 1 - frontend/packages/metal3-plugin/src/plugin.ts | 2 - .../package.json | 1 - .../src/plugin.ts | 2 - .../operator-lifecycle-manager/package.json | 1 - .../operator-lifecycle-manager/src/plugin.ts | 2 - .../packages/pipelines-plugin/package.json | 1 - .../packages/pipelines-plugin/src/plugin.ts | 2 - .../packages/shipwright-plugin/package.json | 1 - .../packages/shipwright-plugin/src/plugin.ts | 2 - frontend/packages/topology/package.json | 1 - frontend/packages/topology/src/plugin.ts | 2 - frontend/packages/vsphere-plugin/package.json | 1 - .../packages/vsphere-plugin/src/plugin.ts | 2 - .../packages/webterminal-plugin/package.json | 1 - .../packages/webterminal-plugin/src/plugin.ts | 2 - 35 files changed, 19 insertions(+), 147 deletions(-) delete mode 100644 frontend/packages/console-app/src/plugin.ts delete mode 100644 frontend/packages/console-telemetry-plugin/src/plugin.ts delete mode 100644 frontend/packages/container-security/src/plugin.ts delete mode 100755 frontend/packages/dev-console/src/plugin.ts delete mode 100644 frontend/packages/helm-plugin/src/plugin.ts delete mode 100644 frontend/packages/insights-plugin/src/plugin.ts delete mode 100644 frontend/packages/knative-plugin/src/plugin.ts delete mode 100644 frontend/packages/metal3-plugin/src/plugin.ts delete mode 100644 frontend/packages/operator-lifecycle-manager-v1/src/plugin.ts delete mode 100644 frontend/packages/operator-lifecycle-manager/src/plugin.ts delete mode 100644 frontend/packages/pipelines-plugin/src/plugin.ts delete mode 100644 frontend/packages/shipwright-plugin/src/plugin.ts delete mode 100644 frontend/packages/topology/src/plugin.ts delete mode 100644 frontend/packages/vsphere-plugin/src/plugin.ts delete mode 100644 frontend/packages/webterminal-plugin/src/plugin.ts diff --git a/frontend/packages/console-app/package.json b/frontend/packages/console-app/package.json index 44fb122b930..9380130dfbd 100644 --- a/frontend/packages/console-app/package.json +++ b/frontend/packages/console-app/package.json @@ -27,7 +27,6 @@ "@console/webterminal-plugin": "0.0.0-fixed" }, "consolePlugin": { - "entry": "src/plugin.ts", "exposedModules": { "tourContext": "src/components/tour/tour-context.ts", "quickStartContext": "src/components/quick-starts/utils/quick-start-context.tsx", diff --git a/frontend/packages/console-app/src/plugin.ts b/frontend/packages/console-app/src/plugin.ts deleted file mode 100644 index ef8d3ac4f8a..00000000000 --- a/frontend/packages/console-app/src/plugin.ts +++ /dev/null @@ -1,2 +0,0 @@ -// See console-extensions.json instead -export default []; diff --git a/frontend/packages/console-plugin-sdk/src/codegen/__tests__/active-plugins.spec.ts b/frontend/packages/console-plugin-sdk/src/codegen/__tests__/active-plugins.spec.ts index bb7d7788504..d16c8c75373 100644 --- a/frontend/packages/console-plugin-sdk/src/codegen/__tests__/active-plugins.spec.ts +++ b/frontend/packages/console-plugin-sdk/src/codegen/__tests__/active-plugins.spec.ts @@ -35,14 +35,14 @@ describe('getActivePluginsModule', () => { ...getTemplatePackage({ name: 'foo', }), - consolePlugin: { entry: 'src/plugin.ts' }, + consolePlugin: {}, }; const barPluginPackage: PluginPackage = { ...getTemplatePackage({ name: 'bar-plugin', }), - consolePlugin: { entry: 'index.ts' }, + consolePlugin: {}, }; const fooDynamicExtensions: Extension[] = [{ type: 'Dynamic/Foo', properties: { test: true } }]; @@ -118,14 +118,14 @@ describe('loadActivePluginsForTestPurposes', () => { ...getTemplatePackage({ name: 'foo', }), - consolePlugin: { entry: 'src/plugin.ts' }, + consolePlugin: {}, }; const barPluginPackage: PluginPackage = { ...getTemplatePackage({ name: 'bar-plugin', }), - consolePlugin: { entry: 'index.ts' }, + consolePlugin: {}, }; const fooStaticExtensions: Extension[] = [{ type: 'Static/Foo', properties: { test: true } }]; @@ -186,7 +186,7 @@ describe('getExecutableCodeRefSource', () => { exposedModules: { [moduleName: string]: string } = {}, ): PluginPackage => ({ ...getTemplatePackage({ name }), - consolePlugin: { entry: 'src/plugin.ts', exposedModules }, + consolePlugin: { exposedModules }, }); it('transforms encoded code reference into CodeRef function source', () => { @@ -270,7 +270,7 @@ describe('getDynamicExtensions', () => { ...getTemplatePackage({ name: 'test-plugin', }), - consolePlugin: { entry: 'src/plugin.ts' }, + consolePlugin: {}, }; const extensionsJSON: Extension[] = [ @@ -357,7 +357,7 @@ describe('getDynamicExtensions', () => { ...getTemplatePackage({ name: 'test-plugin', }), - consolePlugin: { entry: 'src/plugin.ts' }, + consolePlugin: {}, }; const extensionsFilePath = `${pluginPackage._path}/${extensionsFile}`; @@ -383,7 +383,7 @@ describe('getDynamicExtensions', () => { ...getTemplatePackage({ name: 'test-plugin', }), - consolePlugin: { entry: 'src/plugin.ts' }, + consolePlugin: {}, }; const extensionsJSON: Extension[] = []; @@ -419,7 +419,7 @@ describe('getDynamicExtensions', () => { ...getTemplatePackage({ name: 'test-plugin', }), - consolePlugin: { entry: 'src/plugin.ts' }, + consolePlugin: {}, }; const extensionsJSON: Extension[] = [ diff --git a/frontend/packages/console-plugin-sdk/src/codegen/__tests__/plugin-resolver.spec.ts b/frontend/packages/console-plugin-sdk/src/codegen/__tests__/plugin-resolver.spec.ts index cf2a25ca27f..16a44ba68d6 100644 --- a/frontend/packages/console-plugin-sdk/src/codegen/__tests__/plugin-resolver.spec.ts +++ b/frontend/packages/console-plugin-sdk/src/codegen/__tests__/plugin-resolver.spec.ts @@ -20,33 +20,6 @@ describe('isPluginPackage', () => { }), ).toBe(false); }); - - it('returns false if package.consolePlugin.entry is missing', () => { - expect( - isPluginPackage({ - ...getTemplatePackage(), - consolePlugin: {}, - }), - ).toBe(false); - }); - - it('returns false if package.consolePlugin.entry is an empty string', () => { - expect( - isPluginPackage({ - ...getTemplatePackage(), - consolePlugin: { entry: '' }, - }), - ).toBe(false); - }); - - it('returns true if package.consolePlugin.entry is a non-empty string', () => { - expect( - isPluginPackage({ - ...getTemplatePackage(), - consolePlugin: { entry: 'plugin.ts' }, - }), - ).toBe(true); - }); }); describe('readPackages', () => { @@ -75,7 +48,7 @@ describe('readPackages', () => { name: '@console/foo-plugin', _path: pluginPackagePath, }), - consolePlugin: { entry: 'plugin.ts' }, + consolePlugin: {}, }; const utilsPackagePath = '/test/packages/bar-utils'; @@ -132,14 +105,14 @@ describe('filterActivePluginPackages', () => { name: 'bar', version: '1.2.3', }), - consolePlugin: { entry: 'plugin.ts' }, + consolePlugin: {}, }, { ...getTemplatePackage({ name: 'qux', version: '2.3.4', }), - consolePlugin: { entry: 'plugin.ts' }, + consolePlugin: {}, }, ]; @@ -152,7 +125,7 @@ describe('filterActivePluginPackages', () => { name: 'app', }), dependencies: {}, - consolePlugin: { entry: 'plugin.ts' }, + consolePlugin: {}, }; expect(filterActivePluginPackages(appPackage, [appPackage])).toEqual([appPackage]); @@ -167,7 +140,7 @@ describe('filterActivePluginPackages', () => { bar: '1.2.3', qux: '2.3.4', }, - consolePlugin: { entry: 'plugin.ts' }, + consolePlugin: {}, }; const pluginPackages: PluginPackage[] = [ @@ -176,14 +149,14 @@ describe('filterActivePluginPackages', () => { name: 'bar', version: '1.2.3', }), - consolePlugin: { entry: 'plugin.ts' }, + consolePlugin: {}, }, { ...getTemplatePackage({ name: 'qux', version: '2.3.4', }), - consolePlugin: { entry: 'plugin.ts' }, + consolePlugin: {}, }, ]; diff --git a/frontend/packages/console-plugin-sdk/src/codegen/active-plugins.ts b/frontend/packages/console-plugin-sdk/src/codegen/active-plugins.ts index 2ccc0e5480b..fcca1774d60 100644 --- a/frontend/packages/console-plugin-sdk/src/codegen/active-plugins.ts +++ b/frontend/packages/console-plugin-sdk/src/codegen/active-plugins.ts @@ -57,10 +57,7 @@ export const getActivePluginsModule = ( ${output} activePlugins.push({ name: '${pkg.name}', - extensions: [ - ...require('${pkg.name}/${pkg.consolePlugin.entry}').default, - ...${extensionHook(pkg)}, - ], + extensions: ${extensionHook(pkg)}, }); `; } @@ -87,11 +84,7 @@ export const loadActivePluginsForTestPurposes = ( for (const pkg of pluginPackages) { activePlugins.push({ name: pkg.name, - extensions: [ - // eslint-disable-next-line @typescript-eslint/no-var-requires - ...require(`${pkg.name}/${pkg.consolePlugin.entry}`).default, - ...extensionHook(pkg), - ], + extensions: extensionHook(pkg), }); } diff --git a/frontend/packages/console-plugin-sdk/src/codegen/plugin-resolver.ts b/frontend/packages/console-plugin-sdk/src/codegen/plugin-resolver.ts index b1ba063416d..b805830241c 100644 --- a/frontend/packages/console-plugin-sdk/src/codegen/plugin-resolver.ts +++ b/frontend/packages/console-plugin-sdk/src/codegen/plugin-resolver.ts @@ -20,12 +20,7 @@ const consolePluginOverrideEnvVar = 'CONSOLE_PLUGINS'; * Return `true` if the given package represents a Console plugin. */ export const isPluginPackage = (pkg: Package): pkg is PluginPackage => { - if (!(pkg as PluginPackage).consolePlugin) { - return false; - } - - const { entry } = (pkg as PluginPackage).consolePlugin; - return typeof entry === 'string' && !!entry; + return !!pkg.consolePlugin && typeof pkg.consolePlugin === 'object'; }; /** @@ -114,7 +109,6 @@ export type Package = readPkg.NormalizedPackageJson & { export type PluginPackage = Package & { consolePlugin: { - entry: string; exposedModules?: { [moduleName: string]: string }; }; }; diff --git a/frontend/packages/console-plugin-sdk/src/typings/base.ts b/frontend/packages/console-plugin-sdk/src/typings/base.ts index 73af23b50c5..23f44268558 100644 --- a/frontend/packages/console-plugin-sdk/src/typings/base.ts +++ b/frontend/packages/console-plugin-sdk/src/typings/base.ts @@ -8,47 +8,6 @@ import { export type { ExtensionFlags, Extension, ExtensionTypeGuard, LoadedExtension }; -/** - * From plugin author perspective, a plugin is simply a list of extensions. - * - * Plugin metadata is stored in the `package.json` file of the corresponding - * monorepo package. The `consolePlugin.entry` path should point to a module - * that exports the plugin object. - * - * ```json - * { - * "name": "@console/my-cool-plugin", - * "version": "0.0.0-fixed", - * // scripts, dependencies, etc. - * "consolePlugin": { - * "entry": "src/plugin.ts" - * } - * } - * ``` - * - * For better type checking and code completion, use a type parameter that - * represents the union of all the extension types consumed by the plugin: - * - * ```ts - * // packages/my-cool-plugin/src/plugin.ts - * import { Plugin } from '@console/plugin-sdk'; - * - * const plugin: Plugin = [ - * { - * type: 'Foo', - * properties: {} // Foo extension specific properties - * }, - * { - * type: 'Bar', - * properties: {} // Bar extension specific properties - * } - * ]; - * - * export default plugin; - * ``` - */ -export type Plugin = E[]; - /** * Common interface for loading async React components. */ diff --git a/frontend/packages/console-telemetry-plugin/package.json b/frontend/packages/console-telemetry-plugin/package.json index 2036e164e8b..c1fdd82ce1c 100644 --- a/frontend/packages/console-telemetry-plugin/package.json +++ b/frontend/packages/console-telemetry-plugin/package.json @@ -5,7 +5,6 @@ "private": true, "scripts": {}, "consolePlugin": { - "entry": "src/plugin.ts", "displayName": "Telemetry Plugin", "description": "An OpenShift Console plugin for capturing events in segment.", "exposedModules": { diff --git a/frontend/packages/console-telemetry-plugin/src/plugin.ts b/frontend/packages/console-telemetry-plugin/src/plugin.ts deleted file mode 100644 index 344e1486224..00000000000 --- a/frontend/packages/console-telemetry-plugin/src/plugin.ts +++ /dev/null @@ -1,3 +0,0 @@ -const plugin = []; - -export default plugin; diff --git a/frontend/packages/container-security/package.json b/frontend/packages/container-security/package.json index b6fc872eddb..69cc995060e 100644 --- a/frontend/packages/container-security/package.json +++ b/frontend/packages/container-security/package.json @@ -8,7 +8,6 @@ "@console/plugin-sdk": "0.0.0-fixed" }, "consolePlugin": { - "entry": "src/plugin.ts", "exposedModules": { "containerSecurityComponent": "src/components/image-manifest-vuln.tsx", "summary": "src/components/summary.tsx" diff --git a/frontend/packages/container-security/src/plugin.ts b/frontend/packages/container-security/src/plugin.ts deleted file mode 100644 index ef8d3ac4f8a..00000000000 --- a/frontend/packages/container-security/src/plugin.ts +++ /dev/null @@ -1,2 +0,0 @@ -// See console-extensions.json instead -export default []; diff --git a/frontend/packages/dev-console/package.json b/frontend/packages/dev-console/package.json index bbe6367f574..c979f25cdeb 100644 --- a/frontend/packages/dev-console/package.json +++ b/frontend/packages/dev-console/package.json @@ -17,7 +17,6 @@ "@console/plugin-sdk": "0.0.0-fixed" }, "consolePlugin": { - "entry": "src/plugin.ts", "exposedModules": { "providers": "src/actions/providers.tsx", "useDevfile": "src/components/catalog/providers/useDevfile.tsx", diff --git a/frontend/packages/dev-console/src/plugin.ts b/frontend/packages/dev-console/src/plugin.ts deleted file mode 100755 index ef8d3ac4f8a..00000000000 --- a/frontend/packages/dev-console/src/plugin.ts +++ /dev/null @@ -1,2 +0,0 @@ -// See console-extensions.json instead -export default []; diff --git a/frontend/packages/helm-plugin/package.json b/frontend/packages/helm-plugin/package.json index d6a23e4b590..b2e13ba67e8 100644 --- a/frontend/packages/helm-plugin/package.json +++ b/frontend/packages/helm-plugin/package.json @@ -9,7 +9,6 @@ "test": "yarn --cwd ../.. test packages/helm-plugin" }, "consolePlugin": { - "entry": "src/plugin.ts", "exposedModules": { "helmProviderActions": "src/actions/providers.ts", "helmChartProvider": "src/catalog/providers/useHelmCharts.tsx", diff --git a/frontend/packages/helm-plugin/src/plugin.ts b/frontend/packages/helm-plugin/src/plugin.ts deleted file mode 100644 index 344e1486224..00000000000 --- a/frontend/packages/helm-plugin/src/plugin.ts +++ /dev/null @@ -1,3 +0,0 @@ -const plugin = []; - -export default plugin; diff --git a/frontend/packages/insights-plugin/package.json b/frontend/packages/insights-plugin/package.json index 6c5eef9213b..3757d15811f 100644 --- a/frontend/packages/insights-plugin/package.json +++ b/frontend/packages/insights-plugin/package.json @@ -13,7 +13,6 @@ "@console/shared": "0.0.0-fixed" }, "consolePlugin": { - "entry": "src/plugin.ts", "exposedModules": { "status": "src/components/InsightsPopup/status.ts", "InsightsPopup": "src/components/InsightsPopup/index.tsx" diff --git a/frontend/packages/insights-plugin/src/plugin.ts b/frontend/packages/insights-plugin/src/plugin.ts deleted file mode 100644 index ef8d3ac4f8a..00000000000 --- a/frontend/packages/insights-plugin/src/plugin.ts +++ /dev/null @@ -1,2 +0,0 @@ -// See console-extensions.json instead -export default []; diff --git a/frontend/packages/knative-plugin/package.json b/frontend/packages/knative-plugin/package.json index 3efe003e95a..155372f106a 100644 --- a/frontend/packages/knative-plugin/package.json +++ b/frontend/packages/knative-plugin/package.json @@ -14,7 +14,6 @@ "@console/topology": "0.0.0-fixed" }, "consolePlugin": { - "entry": "src/plugin.ts", "exposedModules": { "actions": "src/actions/providers.ts", "icons": "src/utils/icons.tsx", diff --git a/frontend/packages/knative-plugin/src/plugin.ts b/frontend/packages/knative-plugin/src/plugin.ts deleted file mode 100644 index ef8d3ac4f8a..00000000000 --- a/frontend/packages/knative-plugin/src/plugin.ts +++ /dev/null @@ -1,2 +0,0 @@ -// See console-extensions.json instead -export default []; diff --git a/frontend/packages/metal3-plugin/package.json b/frontend/packages/metal3-plugin/package.json index 6d9e9771687..05afcacc8d0 100644 --- a/frontend/packages/metal3-plugin/package.json +++ b/frontend/packages/metal3-plugin/package.json @@ -10,7 +10,6 @@ "pkijs": "^2.1.90" }, "consolePlugin": { - "entry": "src/plugin.ts", "exposedModules": { "nodeActions": "src/components/maintenance/actions.tsx", "features": "src/features.ts", diff --git a/frontend/packages/metal3-plugin/src/plugin.ts b/frontend/packages/metal3-plugin/src/plugin.ts deleted file mode 100644 index ef8d3ac4f8a..00000000000 --- a/frontend/packages/metal3-plugin/src/plugin.ts +++ /dev/null @@ -1,2 +0,0 @@ -// See console-extensions.json instead -export default []; diff --git a/frontend/packages/operator-lifecycle-manager-v1/package.json b/frontend/packages/operator-lifecycle-manager-v1/package.json index 27624705173..0725fee53bb 100644 --- a/frontend/packages/operator-lifecycle-manager-v1/package.json +++ b/frontend/packages/operator-lifecycle-manager-v1/package.json @@ -4,7 +4,6 @@ "description": "A management framework for extending Kubernetes with Operators", "private": true, "consolePlugin": { - "entry": "src/plugin.ts", "exposedModules": { "ExtensionCatalog": "src/components/ExtensionCatalog.tsx", "useExtensionCatalogDatabaseContextValues": "src/contexts/useExtensionCatalogDatabaseContextValues.ts", diff --git a/frontend/packages/operator-lifecycle-manager-v1/src/plugin.ts b/frontend/packages/operator-lifecycle-manager-v1/src/plugin.ts deleted file mode 100644 index ef8d3ac4f8a..00000000000 --- a/frontend/packages/operator-lifecycle-manager-v1/src/plugin.ts +++ /dev/null @@ -1,2 +0,0 @@ -// See console-extensions.json instead -export default []; diff --git a/frontend/packages/operator-lifecycle-manager/package.json b/frontend/packages/operator-lifecycle-manager/package.json index fae59d51703..4664a140c2c 100644 --- a/frontend/packages/operator-lifecycle-manager/package.json +++ b/frontend/packages/operator-lifecycle-manager/package.json @@ -8,7 +8,6 @@ "@console/plugin-sdk": "0.0.0-fixed" }, "consolePlugin": { - "entry": "src/plugin.ts", "exposedModules": { "CatalogRedirect": "src/components/catalog-redirect.tsx", "catalogSource": "src/components/catalog-source.tsx", diff --git a/frontend/packages/operator-lifecycle-manager/src/plugin.ts b/frontend/packages/operator-lifecycle-manager/src/plugin.ts deleted file mode 100644 index ef8d3ac4f8a..00000000000 --- a/frontend/packages/operator-lifecycle-manager/src/plugin.ts +++ /dev/null @@ -1,2 +0,0 @@ -// See console-extensions.json instead -export default []; diff --git a/frontend/packages/pipelines-plugin/package.json b/frontend/packages/pipelines-plugin/package.json index 821c8349348..09570a22f4d 100644 --- a/frontend/packages/pipelines-plugin/package.json +++ b/frontend/packages/pipelines-plugin/package.json @@ -13,7 +13,6 @@ "@console/plugin-sdk": "0.0.0-fixed" }, "consolePlugin": { - "entry": "src/plugin.ts", "exposedModules": { "icons": "src/utils/icons.tsx", "yamlTemplates": "src/templates/pipelines.ts", diff --git a/frontend/packages/pipelines-plugin/src/plugin.ts b/frontend/packages/pipelines-plugin/src/plugin.ts deleted file mode 100644 index ef8d3ac4f8a..00000000000 --- a/frontend/packages/pipelines-plugin/src/plugin.ts +++ /dev/null @@ -1,2 +0,0 @@ -// See console-extensions.json instead -export default []; diff --git a/frontend/packages/shipwright-plugin/package.json b/frontend/packages/shipwright-plugin/package.json index 9bf3579ceff..0b81e3cc6e6 100644 --- a/frontend/packages/shipwright-plugin/package.json +++ b/frontend/packages/shipwright-plugin/package.json @@ -12,7 +12,6 @@ "@kubernetes-models/shipwright": "^0.2.0" }, "consolePlugin": { - "entry": "src/plugin.ts", "exposedModules": { "pages": "src/pages.ts", "actions": "src/actions.ts", diff --git a/frontend/packages/shipwright-plugin/src/plugin.ts b/frontend/packages/shipwright-plugin/src/plugin.ts deleted file mode 100644 index ef8d3ac4f8a..00000000000 --- a/frontend/packages/shipwright-plugin/src/plugin.ts +++ /dev/null @@ -1,2 +0,0 @@ -// See console-extensions.json instead -export default []; diff --git a/frontend/packages/topology/package.json b/frontend/packages/topology/package.json index 8be6b228cf0..8ca03a2f8c4 100644 --- a/frontend/packages/topology/package.json +++ b/frontend/packages/topology/package.json @@ -16,7 +16,6 @@ "@console/dev-console": "0.0.0-fixed" }, "consolePlugin": { - "entry": "src/plugin.ts", "exposedModules": { "BuildTabSection": "src/components/workload/build-tab-section.tsx", "CronJobSideBarDetails": "src/components/workload/CronJobSideBarDetails.tsx", diff --git a/frontend/packages/topology/src/plugin.ts b/frontend/packages/topology/src/plugin.ts deleted file mode 100644 index ef8d3ac4f8a..00000000000 --- a/frontend/packages/topology/src/plugin.ts +++ /dev/null @@ -1,2 +0,0 @@ -// See console-extensions.json instead -export default []; diff --git a/frontend/packages/vsphere-plugin/package.json b/frontend/packages/vsphere-plugin/package.json index e96c79d5012..b9813eb523a 100644 --- a/frontend/packages/vsphere-plugin/package.json +++ b/frontend/packages/vsphere-plugin/package.json @@ -12,7 +12,6 @@ "yup": "^0.27.0" }, "consolePlugin": { - "entry": "src/plugin.ts", "exposedModules": { "vsphereStatus": "src/components/ClusterOverview/VSphereStatus.tsx", "flag": "src/flag.ts" diff --git a/frontend/packages/vsphere-plugin/src/plugin.ts b/frontend/packages/vsphere-plugin/src/plugin.ts deleted file mode 100644 index ef8d3ac4f8a..00000000000 --- a/frontend/packages/vsphere-plugin/src/plugin.ts +++ /dev/null @@ -1,2 +0,0 @@ -// See console-extensions.json instead -export default []; diff --git a/frontend/packages/webterminal-plugin/package.json b/frontend/packages/webterminal-plugin/package.json index 4601307cf69..f6b95bfcfef 100644 --- a/frontend/packages/webterminal-plugin/package.json +++ b/frontend/packages/webterminal-plugin/package.json @@ -10,7 +10,6 @@ }, "dependencies": {}, "consolePlugin": { - "entry": "src/plugin.ts", "exposedModules": { "useWebTerminalProvider": "src/actions/providers/web-terminal-provider.ts", "reduxReducer": "src/redux/reducer.ts", diff --git a/frontend/packages/webterminal-plugin/src/plugin.ts b/frontend/packages/webterminal-plugin/src/plugin.ts deleted file mode 100644 index ef8d3ac4f8a..00000000000 --- a/frontend/packages/webterminal-plugin/src/plugin.ts +++ /dev/null @@ -1,2 +0,0 @@ -// See console-extensions.json instead -export default [];