From 7307b76bba28eac19fb4e85f554cfb0c0d261592 Mon Sep 17 00:00:00 2001 From: Kevin Cormier Date: Fri, 29 Nov 2024 17:18:41 -0500 Subject: [PATCH 1/2] Make OpenShift console Timestamp component available Signed-off-by: Kevin Cormier --- .../components/ACMNotReadyWarning.test.tsx | 25 ++----------- .../src/components/PluginContextProvider.tsx | 28 +++++---------- frontend/src/lib/PluginContext.tsx | 35 ++++++++++++------- frontend/src/lib/test-util.ts | 6 ---- .../ApplicationDetails.test.tsx | 8 ++--- .../src/routes/Applications/Overview.test.tsx | 8 ++--- .../routes/Home/Overview/Overview.test.tsx | 23 ++---------- .../ClusterSetDetails.test.tsx | 8 ++--- .../Clusters/ClusterSets/ClusterSets.test.tsx | 8 ++--- .../CreateCluster/CreateCluster.test.tsx | 6 ++-- .../ImportCluster/ImportCluster.test.tsx | 6 ++-- .../components/StatusSummaryCount.test.tsx | 7 ++-- 12 files changed, 56 insertions(+), 112 deletions(-) diff --git a/frontend/src/components/ACMNotReadyWarning.test.tsx b/frontend/src/components/ACMNotReadyWarning.test.tsx index b0439b88a5e..7ae53c094e0 100644 --- a/frontend/src/components/ACMNotReadyWarning.test.tsx +++ b/frontend/src/components/ACMNotReadyWarning.test.tsx @@ -7,8 +7,7 @@ import { clickByRole, waitForText } from '../lib/test-util' import { SubscriptionOperator, SubscriptionOperatorApiVersion, SubscriptionOperatorKind } from '../resources' import { nockIgnoreOperatorCheck } from '../lib/nock-util' import { ACMNotReadyWarning } from './ACMNotReadyWarning' -import { PluginDataContext } from '../lib/PluginDataContext' -import { PluginContext } from '../lib/PluginContext' +import { defaultPlugin, PluginContext } from '../lib/PluginContext' const acm_unhealthy: SubscriptionOperator = { apiVersion: SubscriptionOperatorApiVersion, @@ -88,17 +87,8 @@ describe('ACMNotReadyWarning', () => { render( [[] as any, true, undefined], - }, }} > @@ -125,17 +115,8 @@ describe('ACMNotReadyWarning', () => { render( [[] as any, true, undefined], - }, }} > diff --git a/frontend/src/components/PluginContextProvider.tsx b/frontend/src/components/PluginContextProvider.tsx index 4350f1366dd..6227f87b186 100644 --- a/frontend/src/components/PluginContextProvider.tsx +++ b/frontend/src/components/PluginContextProvider.tsx @@ -1,7 +1,12 @@ /* Copyright Contributors to the Open Cluster Management project */ -import { isHrefNavItem, useResolvedExtensions, UseK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk' +import { + isHrefNavItem, + Timestamp, + useK8sWatchResource, + useResolvedExtensions, +} from '@openshift-console/dynamic-plugin-sdk' import { AcmTablePaginationContextProvider, AcmToastGroup, AcmToastProvider } from '../ui-components' -import { ReactNode, useMemo, useEffect, useState } from 'react' +import { ReactNode, useMemo } from 'react' import { PluginContext } from '../lib/PluginContext' import { useAcmExtension } from '../plugin-extensions/handler' import { LoadingPage } from './LoadingPage' @@ -15,9 +20,6 @@ const isPluginDataContext = (e: Extension): e is SharedContext => isSharedContext(e) && e.properties.id === 'mce-data-context' export function PluginContextProvider(props: { children?: ReactNode }) { - const [ocpApi, setOcpApi] = useState<{ useK8sWatchResource: UseK8sWatchResource }>({ - useK8sWatchResource: () => [[] as any, false, undefined], - }) const [hrefs] = useResolvedExtensions(isHrefNavItem) const [pluginDataContexts, extensionsReady] = useResolvedExtensions(isPluginDataContext) @@ -38,20 +40,6 @@ export function PluginContextProvider(props: { children?: ReactNode }) { const isACMAvailable = isOverviewAvailable const isSubmarinerAvailable = isOverviewAvailable - useEffect(() => { - const loadOCPAPI = async () => { - try { - const api = await import('@openshift-console/dynamic-plugin-sdk') - setOcpApi({ - useK8sWatchResource: api.useK8sWatchResource, - }) - } catch (err) { - console.error('Failed to load OCP API', err) - } - } - loadOCPAPI() - }, []) - // ACM Custom extensions const acmExtensions = useAcmExtension() @@ -66,7 +54,7 @@ export function PluginContextProvider(props: { children?: ReactNode }) { isSubmarinerAvailable, dataContext: pluginDataContext.properties.context, acmExtensions, - ocpApi, + ocpApi: { Timestamp, useK8sWatchResource }, }} > diff --git a/frontend/src/lib/PluginContext.tsx b/frontend/src/lib/PluginContext.tsx index 933d8068c3d..f00701a7715 100644 --- a/frontend/src/lib/PluginContext.tsx +++ b/frontend/src/lib/PluginContext.tsx @@ -1,22 +1,25 @@ /* Copyright Contributors to the Open Cluster Management project */ -import { Context, createContext } from 'react' +import { Context, createContext, FC } from 'react' import { AcmExtension } from '../plugin-extensions/types' import { PluginData, PluginDataContext } from './PluginDataContext' -import { UseK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk/lib/extensions/console-types' +import { TimestampProps, UseK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk/lib/extensions/console-types' -export const PluginContext = createContext<{ - isACMAvailable?: boolean - isOverviewAvailable?: boolean - isSubmarinerAvailable?: boolean - isApplicationsAvailable?: boolean - isGovernanceAvailable?: boolean - isSearchAvailable?: boolean +export type Plugin = { + isACMAvailable: boolean + isOverviewAvailable: boolean + isSubmarinerAvailable: boolean + isApplicationsAvailable: boolean + isGovernanceAvailable: boolean + isSearchAvailable: boolean dataContext: Context - acmExtensions?: AcmExtension + acmExtensions: AcmExtension ocpApi: { + Timestamp: FC useK8sWatchResource: UseK8sWatchResource } -}>({ +} + +export const defaultPlugin: Plugin = { isACMAvailable: true, isOverviewAvailable: true, isSubmarinerAvailable: true, @@ -26,6 +29,14 @@ export const PluginContext = createContext<{ dataContext: PluginDataContext, acmExtensions: {}, ocpApi: { + // TODO: implement basic version of timestamp (e.g. without translation and relative times) for local development + Timestamp: () => ( +
+ TODO: implement <Timestamp /> component for standalone dev console +
+ ), useK8sWatchResource: () => [[] as any, true, undefined], }, -}) +} + +export const PluginContext = createContext(defaultPlugin) diff --git a/frontend/src/lib/test-util.ts b/frontend/src/lib/test-util.ts index d2281204397..e6c56f52f8e 100644 --- a/frontend/src/lib/test-util.ts +++ b/frontend/src/lib/test-util.ts @@ -3,7 +3,6 @@ import { act, ByRoleMatcher, ByRoleOptions, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { Scope } from 'nock/types' -import { UseK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk' export const waitTimeout = 5 * 1000 @@ -375,11 +374,6 @@ export function isCardEnabled(card: HTMLElement) { return card.style.cursor === 'pointer' } -export const ocpApi: { - useK8sWatchResource: UseK8sWatchResource -} = { - useK8sWatchResource: () => [[] as any, true, undefined], -} export const getCSVExportSpies = () => { const blobConstructorSpy = jest.fn() jest.spyOn(global, 'Blob').mockImplementationOnce(blobConstructorSpy) diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationDetails.test.tsx b/frontend/src/routes/Applications/ApplicationDetails/ApplicationDetails.test.tsx index 69d1550ef91..dfcc5632582 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationDetails.test.tsx +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationDetails.test.tsx @@ -18,9 +18,8 @@ import { subscriptionsState, } from '../../../atoms' import { nockIgnoreApiPaths, nockIgnoreRBAC, nockSearch } from '../../../lib/nock-util' -import { PluginContext } from '../../../lib/PluginContext' -import { PluginDataContext } from '../../../lib/PluginDataContext' -import { ocpApi, waitForText } from '../../../lib/test-util' +import { defaultPlugin, PluginContext } from '../../../lib/PluginContext' +import { waitForText } from '../../../lib/test-util' import { ApplicationActionProps } from '../../../plugin-extensions/properties' import { AcmExtension } from '../../../plugin-extensions/types' import { GetMessagesDocument, SearchSchemaDocument } from '../../Search/search-sdk/search-sdk' @@ -372,9 +371,8 @@ describe('Applications Page', () => { diff --git a/frontend/src/routes/Applications/Overview.test.tsx b/frontend/src/routes/Applications/Overview.test.tsx index 89eec87f740..5ae6fa34a92 100644 --- a/frontend/src/routes/Applications/Overview.test.tsx +++ b/frontend/src/routes/Applications/Overview.test.tsx @@ -12,9 +12,8 @@ import { nockSearch, nockAggegateRequest, } from '../../lib/nock-util' -import { PluginContext } from '../../lib/PluginContext' -import { PluginDataContext } from '../../lib/PluginDataContext' -import { ocpApi, waitForText } from '../../lib/test-util' +import { defaultPlugin, PluginContext } from '../../lib/PluginContext' +import { waitForText } from '../../lib/test-util' import { ApplicationKind, ApplicationSetKind, @@ -116,9 +115,8 @@ describe('Applications Page', () => { diff --git a/frontend/src/routes/Home/Overview/Overview.test.tsx b/frontend/src/routes/Home/Overview/Overview.test.tsx index 957667e57ef..34fef564f26 100644 --- a/frontend/src/routes/Home/Overview/Overview.test.tsx +++ b/frontend/src/routes/Home/Overview/Overview.test.tsx @@ -5,8 +5,7 @@ import { render } from '@testing-library/react' import { MemoryRouter } from 'react-router-dom-v5-compat' import { RecoilRoot } from 'recoil' import { nockGet, nockIgnoreApiPaths } from '../../../lib/nock-util' -import { PluginContext } from '../../../lib/PluginContext' -import { PluginDataContext } from '../../../lib/PluginDataContext' +import { defaultPlugin, PluginContext } from '../../../lib/PluginContext' import { clickByText, waitForNocks, waitForText } from '../../../lib/test-util' import Overview from './Overview' import { getAddonRequest, getAddonResponse } from './Overview.sharedmocks' @@ -29,13 +28,8 @@ it('should render overview page with extension', async () => { { }, ], }, - ocpApi: { - useK8sWatchResource: () => [[] as any, true, undefined], - }, }} > @@ -81,13 +72,8 @@ it('should render overview page layout when extension tab crashes', async () => }, ], }, - ocpApi: { - useK8sWatchResource: () => [[] as any, true, undefined], - }, }} > diff --git a/frontend/src/routes/Infrastructure/Clusters/ClusterSets/ClusterSetDetails/ClusterSetDetails.test.tsx b/frontend/src/routes/Infrastructure/Clusters/ClusterSets/ClusterSetDetails/ClusterSetDetails.test.tsx index 353f727f1dc..84b465c919c 100644 --- a/frontend/src/routes/Infrastructure/Clusters/ClusterSets/ClusterSetDetails/ClusterSetDetails.test.tsx +++ b/frontend/src/routes/Infrastructure/Clusters/ClusterSets/ClusterSetDetails/ClusterSetDetails.test.tsx @@ -25,8 +25,7 @@ import { nockNamespacedList, nockPatch, } from '../../../../../lib/nock-util' -import { PluginContext } from '../../../../../lib/PluginContext' -import { PluginDataContext } from '../../../../../lib/PluginDataContext' +import { defaultPlugin, PluginContext } from '../../../../../lib/PluginContext' import { mockGlobalManagedClusterSet, mockManagedClusterSet } from '../../../../../lib/test-metadata' import { clearByTestId, @@ -39,7 +38,6 @@ import { waitForNotText, waitForTestId, waitForText, - ocpApi, } from '../../../../../lib/test-util' import { NavigationPath } from '../../../../../NavigationPath' import { @@ -2084,7 +2082,7 @@ describe('ClusterSetDetails page without Submariner', () => { nockIgnoreRBAC() nockIgnoreApiPaths() render( - + ) @@ -2108,7 +2106,7 @@ describe('ClusterSetDetails page global clusterset', () => { nockIgnoreRBAC() nockIgnoreApiPaths() render( - + ) diff --git a/frontend/src/routes/Infrastructure/Clusters/ClusterSets/ClusterSets.test.tsx b/frontend/src/routes/Infrastructure/Clusters/ClusterSets/ClusterSets.test.tsx index 565189ab065..3bc990b54ef 100644 --- a/frontend/src/routes/Infrastructure/Clusters/ClusterSets/ClusterSets.test.tsx +++ b/frontend/src/routes/Infrastructure/Clusters/ClusterSets/ClusterSets.test.tsx @@ -12,7 +12,7 @@ import { managedClustersState, } from '../../../../atoms' import { nockCreate, nockDelete, nockIgnoreApiPaths, nockIgnoreRBAC } from '../../../../lib/nock-util' -import { PluginContext } from '../../../../lib/PluginContext' +import { defaultPlugin, PluginContext } from '../../../../lib/PluginContext' import { mockManagedClusterSet, mockGlobalClusterSet } from '../../../../lib/test-metadata' import { clickBulkAction, @@ -23,7 +23,6 @@ import { waitForText, waitForNotText, typeByTestId, - ocpApi, clickByLabel, } from '../../../../lib/test-util' import { @@ -31,7 +30,6 @@ import { mockManagedClusterInfos, mockManagedClusters, } from '../ManagedClusters/ManagedClusters.sharedmocks' -import { PluginDataContext } from '../../../../lib/PluginDataContext' import { NavigationPath } from '../../../../NavigationPath' import Clusters from '../Clusters' @@ -95,7 +93,7 @@ describe('ClusterSets page without Submariner', () => { nockIgnoreRBAC() nockIgnoreApiPaths() render( - + ) @@ -111,7 +109,7 @@ describe('ClusterSets page with csv export', () => { nockIgnoreRBAC() nockIgnoreApiPaths() render( - + ) diff --git a/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/CreateCluster/CreateCluster.test.tsx b/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/CreateCluster/CreateCluster.test.tsx index 3018d622bc9..c929a4477a3 100644 --- a/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/CreateCluster/CreateCluster.test.tsx +++ b/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/CreateCluster/CreateCluster.test.tsx @@ -22,14 +22,12 @@ import { nockIgnoreRBAC, nockList, } from '../../../../../lib/nock-util' -import { PluginContext } from '../../../../../lib/PluginContext' -import { PluginDataContext } from '../../../../../lib/PluginDataContext' +import { defaultPlugin, PluginContext } from '../../../../../lib/PluginContext' import { clickByPlaceholderText, clickByRole, clickByTestId, clickByText, - ocpApi, pasteByTestId, typeByPlaceholderText, typeByTestId, @@ -1051,7 +1049,7 @@ describe('CreateCluster AWS', () => { // create the form const { container } = render( - + ) diff --git a/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/ImportCluster/ImportCluster.test.tsx b/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/ImportCluster/ImportCluster.test.tsx index ef18daa7a5e..c858624f6f2 100644 --- a/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/ImportCluster/ImportCluster.test.tsx +++ b/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/ImportCluster/ImportCluster.test.tsx @@ -71,14 +71,12 @@ import { waitForNocks, waitForNotText, waitForText, - ocpApi, } from '../../../../../lib/test-util' import { NavigationPath } from '../../../../../NavigationPath' import DiscoveredClustersPage from '../../DiscoveredClusters/DiscoveredClusters' import ImportClusterPage from './ImportCluster' -import { PluginContext } from '../../../../../lib/PluginContext' +import { defaultPlugin, PluginContext } from '../../../../../lib/PluginContext' import { AcmToastGroup, AcmToastProvider } from '../../../../../ui-components' -import { PluginDataContext } from '../../../../../lib/PluginDataContext' import { PropsWithChildren, useEffect } from 'react' const mockProject: ProjectRequest = { @@ -798,7 +796,7 @@ describe('ImportCluster', () => { const importSecretNock = nockGet(mockSecretResponse) render( - + ) diff --git a/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/components/StatusSummaryCount.test.tsx b/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/components/StatusSummaryCount.test.tsx index 9fac9238577..9971c12051d 100644 --- a/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/components/StatusSummaryCount.test.tsx +++ b/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/components/StatusSummaryCount.test.tsx @@ -5,9 +5,8 @@ import { MemoryRouter, Outlet, Route, Routes } from 'react-router-dom-v5-compat' import { RecoilRoot } from 'recoil' import { policiesState, policyreportState } from '../../../../../atoms' import { nockAggegateRequest, nockSearch } from '../../../../../lib/nock-util' -import { PluginContext } from '../../../../../lib/PluginContext' -import { PluginDataContext } from '../../../../../lib/PluginDataContext' -import { clickByText, waitForNotText, waitForText, ocpApi } from '../../../../../lib/test-util' +import { defaultPlugin, PluginContext } from '../../../../../lib/PluginContext' +import { clickByText, waitForNotText, waitForText } from '../../../../../lib/test-util' import { Policy, PolicyReport } from '../../../../../resources' import { Cluster, ClusterStatus } from '../../../../../resources/utils' import { @@ -330,7 +329,7 @@ describe('StatusSummaryCount', () => { test('renders without applications and governance', async () => { render( From 043cf8f06cb88289c90a2714b0eeb7eaba93326b Mon Sep 17 00:00:00 2001 From: Kevin Cormier Date: Fri, 29 Nov 2024 17:20:24 -0500 Subject: [PATCH 2/2] DEMO: Use the Timestamp component Signed-off-by: Kevin Cormier --- .../ManagedClusters/ManagedClusters.tsx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/ManagedClusters.tsx b/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/ManagedClusters.tsx index 0e1739f3b59..85796adf7f3 100644 --- a/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/ManagedClusters.tsx +++ b/frontend/src/routes/Infrastructure/Clusters/ManagedClusters/ManagedClusters.tsx @@ -86,6 +86,8 @@ import keyBy from 'lodash/keyBy' import { HighlightSearchText } from '../../../../components/HighlightSearchText' import { SearchOperator } from '../../../../ui-components/AcmSearchInput' import { handleStandardComparison, handleSemverOperatorComparison } from '../../../../lib/search-utils' +import { PluginContext } from '../../../../lib/PluginContext' +import { css } from '@emotion/css' const onToggle = (acmCardID: string, setOpen: (open: boolean) => void) => { setOpen(false) @@ -136,11 +138,26 @@ export default function ManagedClusters() { return () => canCreateManagedCluster.abort() }, []) + const { + ocpApi: { Timestamp }, + } = useContext(PluginContext) + return ( onToggle(onBoardingModalID, setOpenOnboardingModal)} /> + + {/* TODO: Create a wrapper component that removes the globe icon. When using the 'simple' prop, the tooltip that shows UTC time in English is also removed. */} + +