diff --git a/src/addresses/address-details/AddressDetails.component.tsx b/src/addresses/address-details/AddressDetails.component.tsx index c2a7b6cc..d4711524 100644 --- a/src/addresses/address-details/AddressDetails.component.tsx +++ b/src/addresses/address-details/AddressDetails.component.tsx @@ -15,7 +15,7 @@ import { import { useTranslation } from '../../i18n/i18n'; import { useJolokiaServiceReadAddressAttributes } from '../../openapi/jolokia/queries'; import { AddressDetailsRow } from './AddressDetailsRow'; -import { AuthContext } from '../../jolokia/customHooks'; +import { AuthContext } from '../../jolokia/context'; type AddressDetailsTableProps = { name: string; @@ -56,7 +56,7 @@ const AddressDetails: FC = ({ name }) => { 'UnRoutedMessageCount', ]; - const authToken = useContext(AuthContext); + const { token: authToken } = useContext(AuthContext); const { data: readAddressAttrs, isSuccess, diff --git a/src/addresses/address-details/AddressDetails.container.tsx b/src/addresses/address-details/AddressDetails.container.tsx index 91f4db73..266d7332 100644 --- a/src/addresses/address-details/AddressDetails.container.tsx +++ b/src/addresses/address-details/AddressDetails.container.tsx @@ -1,33 +1,17 @@ -import { FC, useState } from 'react'; +import { FC } from 'react'; import { Alert, - Button, - Modal, - ModalVariant, PageSection, PageSectionVariants, - Text, - TextContent, - TextVariants, Title, } from '@patternfly/react-core'; import { useTranslation } from '../../i18n/i18n'; -import { AMQBrokerModel } from '../../k8s/models'; -import { - K8sResourceKind, - k8sGet, - useK8sWatchResource, -} from '@openshift-console/dynamic-plugin-sdk'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { OpenAPI as OpenAPIConfig } from '../../openapi/jolokia/requests/core/OpenAPI'; import { AddressDetails } from './AddressDetails.component'; import { AddressDetailsBreadcrumb } from './AddressDetailsBreadcrumb/AddressDetailsBreadcrumb'; -import { - AuthContext, - useGetApiServerBaseUrl, - useJolokiaLogin, -} from '../../jolokia/customHooks'; + import { useParams } from 'react-router-dom-v5-compat'; +import { JolokiaAuthentication } from '../../jolokia/components/JolokiaAuthentication'; +import { UseGetBrokerCR } from '../../k8s/customHooks'; export const AddressDetailsPage: FC = () => { const { t } = useTranslation(); @@ -42,93 +26,16 @@ export const AddressDetailsPage: FC = () => { brokerName?: string; podName?: string; }>(); - const [brokerDetails, setBrokerDetails] = useState({}); - const [_loading, setLoading] = useState(true); - const [isFirstMount, setIsFirstMount] = useState(true); - const [error, setError] = useState(''); - const [isErrorModalOpen, setIsErrorModalOpen] = useState(false); - const [routes] = useK8sWatchResource({ - isList: true, - groupVersionKind: { - group: 'route.openshift.io', - kind: 'Route', - version: 'v1', - }, - namespaced: true, - }); - - const k8sGetBroker = () => { - setLoading(true); - k8sGet({ model: AMQBrokerModel, name: brokerName, ns: namespace }) - .then((broker: K8sResourceKind) => { - setBrokerDetails(broker); - }) - .catch((e) => { - setError(e.message); - }) - .finally(() => { - setLoading(false); - }); - }; - - const handleModalToggle = () => { - setIsErrorModalOpen(!isErrorModalOpen); - }; - - const handleTryAgain = () => { - setIsErrorModalOpen(false); - window.location.reload(); - }; - - if (isFirstMount) { - k8sGetBroker(); - setIsFirstMount(false); - } - const podOrdinal = parseInt(podName.replace(brokerName + '-ss-', '')); - - const { token, isError, isLoading, source } = useJolokiaLogin( - brokerDetails, - routes, - podOrdinal, + const { brokerCr: brokerDetails, error: error } = UseGetBrokerCR( + brokerName, + namespace, ); - const [prevIsLoading, setPrevIsLoading] = useState(isLoading); - const [notify, setNotify] = useState(false); - if (prevIsLoading !== isLoading) { - if (!isLoading && source === 'api') { - setNotify(true); - } - setPrevIsLoading(isLoading); - } - if (notify) { - if (isError) { - setIsErrorModalOpen(true); - } - setNotify(false); - } + const podOrdinal = parseInt(podName.replace(brokerName + '-ss-', '')); return ( - - - {t('try_again')} - , - , - ]} - > - - {t('login_failed_message')} - - + { {error && } - + ); }; export const App: FC = () => { - OpenAPIConfig.BASE = useGetApiServerBaseUrl(); - const querClient = new QueryClient(); - return ( - - - - ); + return ; }; diff --git a/src/brokers/broker-details/BrokerDetails.container.tsx b/src/brokers/broker-details/BrokerDetails.container.tsx index 61cc6f25..34b0d8d2 100644 --- a/src/brokers/broker-details/BrokerDetails.container.tsx +++ b/src/brokers/broker-details/BrokerDetails.container.tsx @@ -1,11 +1,4 @@ -import { FC, useState, useEffect } from 'react'; -import { - GreenCheckCircleIcon, - K8sResourceKind, - RedExclamationCircleIcon, - k8sGet, - useK8sWatchResource, -} from '@openshift-console/dynamic-plugin-sdk'; +import { FC, useContext } from 'react'; import { Tabs, Tab, @@ -13,25 +6,10 @@ import { Title, PageSection, PageSectionVariants, - Spinner, Alert, - Modal, - ModalVariant, - Button, - Text, - TextContent, - TextVariants, + Spinner, } from '@patternfly/react-core'; import { useTranslation } from '../../i18n/i18n'; -import { AMQBrokerModel } from '../../k8s/models'; -import { BrokerCR } from '../../k8s/types'; -import { - AuthContext, - useGetApiServerBaseUrl, - useJolokiaLogin, -} from '../../jolokia/customHooks'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { OpenAPI as OpenAPIConfig } from '../../openapi/jolokia/requests/core/OpenAPI'; import { ClientsContainer } from './components/Clients/Clients.container'; import { AddressContainer } from './components/Addresses/Address.container'; import { BrokerDetailsBreadcrumb } from './components/BrokerDetailsBreadcrumb/BrokerDetailsBreadcrumb'; @@ -48,235 +26,187 @@ import { useNavigate, useParams, } from 'react-router-dom-v5-compat'; +import { JolokiaAuthentication } from '../../jolokia/components/JolokiaAuthentication'; +import { UseGetBrokerCR } from '../../k8s/customHooks'; +import { AuthContext } from '../../jolokia/context'; +import { BrokerCR } from '../../k8s/types'; +import { + GreenCheckCircleIcon, + RedExclamationCircleIcon, +} from '@openshift-console/dynamic-plugin-sdk'; -export const BrokerDetailsPage: FC = () => { +type AuthenticatedPageContentPropType = { + brokerCr: BrokerCR; + brokerName: string; + podName: string; + namespace: string; + loading: boolean; + error: string; +}; +const AuthenticatedPageContent: FC = ({ + brokerCr, + brokerName, + namespace, + podName, + loading: loadingBrokerCr, + error: errorBrokerCr, +}) => { const { t } = useTranslation(); - const { - ns: namespace, - brokerName, - podName, - } = useParams<{ - ns?: string; - brokerName?: string; - podName?: string; - }>(); - const [brokerDetails, setBrokerDetails] = useState({}); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(''); - const [isErrorModalOpen, setIsErrorModalOpen] = useState(false); - const [routes] = useK8sWatchResource({ - isList: true, - groupVersionKind: { - group: 'route.openshift.io', - kind: 'Route', - version: 'v1', - }, - namespaced: true, - }); - const location = useLocation(); - const navigate = useNavigate(); const searchParams = new URLSearchParams(location.search); const activeTabKey = searchParams.get('tab') || 'overview'; - - const k8sGetBroker = () => { - setLoading(true); - k8sGet({ model: AMQBrokerModel, name: brokerName, ns: namespace }) - .then((broker: K8sResourceKind) => { - setBrokerDetails(broker as BrokerCR); - }) - .catch((e) => { - setError(e.message); - }) - .finally(() => { - setLoading(false); - }); - }; - - useEffect(() => { - k8sGetBroker(); - }, []); - - const handleModalToggle = () => { - setIsErrorModalOpen(!isErrorModalOpen); - }; - - const handleTryAgain = () => { - setIsErrorModalOpen(false); - window.location.reload(); - }; - + const navigate = useNavigate(); const handleTabSelect = (_event: any, eventKey: string | number) => { searchParams.set('tab', eventKey.toString()); navigate({ search: searchParams.toString() }); }; - - const podOrdinal = parseInt(podName.replace(brokerName + '-ss-', '')); - - const { token, isSucces, isLoading, isError, source } = useJolokiaLogin( - brokerDetails, - routes, - podOrdinal, - ); - - const [prevIsLoading, setPrevIsLoading] = useState(isLoading); - const [notify, setNotify] = useState(false); - if (prevIsLoading !== isLoading) { - if (!isLoading && source === 'api') { - setNotify(true); - } - setPrevIsLoading(isLoading); - } - if (notify) { - if (isError) { - setIsErrorModalOpen(true); - } - setNotify(false); - } - + const { + isSuccess: isSuccessToken, + isLoading: isLoadingToken, + isError: isErrorToken, + } = useContext(AuthContext); return ( - - - {t('try_again')} - , - , - ]} - > - - {t('login_failed_message')} - - - -
- +
+ + + {t('broker')} {brokerName} {t('/')} {podName} + +
+ {errorBrokerCr && } + + {t('overview')}} + > + - - {t('broker')} {brokerName} {t('/')} {podName} - -
- {error && } - - {t('overview')}} - > - - + + {t('clients')}} + > + + + {t('addresses')}} + > + + + {process.env.NODE_ENV === 'development' && ( {t('clients')}} + eventKey={'jolokiaTestPanel'} + title={ + + {t('check-jolokia ')} + {isLoadingToken && ( + + )} + {isSuccessToken && ( + + )} + {isErrorToken && ( + + )} + + } > - + +
+ )} + {process.env.NODE_ENV === 'development' && ( {t('addresses')}} + eventKey={'jolokia-details'} + title={ + + {t('jolokia-details')} + {isLoadingToken && ( + + )} + {isSuccessToken && ( + + )} + {isErrorToken && ( + + )} + + } > - + + {t('broker')}} + > + + + {t('addresses')}} + > + + + {t('acceptors')}} + > + + + {t('queues')}} + > + + + - {process.env.NODE_ENV === 'development' && ( - - {t('check-jolokia ')} + )} +
+
+ ); +}; +export const BrokerDetailsPage: FC = () => { + const { + ns: namespace, + brokerName, + podName, + } = useParams<{ + ns?: string; + brokerName?: string; + podName?: string; + }>(); - {isLoading && ( - - )} - {isSucces && ( - - )} - {isError && ( - - )} - - } - > - -
- - )} - {process.env.NODE_ENV === 'development' && ( - - {t('-jolokia-details')} + const { brokerCr, isLoading, error } = UseGetBrokerCR(brokerName, namespace); + + const podOrdinal = parseInt(podName.replace(brokerName + '-ss-', '')); - {isLoading && ( - - )} - {isSucces && ( - - )} - {isError && ( - - )} - - } - > - - {t('broker')}} - > - - - {t('addresses')}} - > - - - {t('acceptors')}} - > - - - {t('queues')}} - > - - - - - )} - - -
+ return ( + + + ); }; export const App: FC = () => { - OpenAPIConfig.BASE = useGetApiServerBaseUrl(); - const querClient = new QueryClient(); - return ( - - - - ); + return ; }; diff --git a/src/brokers/broker-details/components/Addresses/Address.container.tsx b/src/brokers/broker-details/components/Addresses/Address.container.tsx index 44d899aa..74edc2f2 100644 --- a/src/brokers/broker-details/components/Addresses/Address.container.tsx +++ b/src/brokers/broker-details/components/Addresses/Address.container.tsx @@ -1,10 +1,10 @@ import { FC, useContext } from 'react'; import { Addresses } from './Address.component'; -import { AuthContext } from '../../../../jolokia/customHooks'; +import { AuthContext } from '../../../../jolokia/context'; import { useJolokiaServiceGetAddresses } from '../../../../openapi/jolokia/queries'; const AddressContainer: FC = () => { - const authToken = useContext(AuthContext); + const { token: authToken } = useContext(AuthContext); const { data: addresses, isSuccess } = useJolokiaServiceGetAddresses({ jolokiaSessionId: authToken, diff --git a/src/brokers/broker-details/components/Addresses/AddressRow.tsx b/src/brokers/broker-details/components/Addresses/AddressRow.tsx index 0e1423fe..07f46997 100644 --- a/src/brokers/broker-details/components/Addresses/AddressRow.tsx +++ b/src/brokers/broker-details/components/Addresses/AddressRow.tsx @@ -6,7 +6,7 @@ import { } from '@openshift-console/dynamic-plugin-sdk'; import { Address } from '../../../../openapi/jolokia/requests'; import { useJolokiaServiceReadAddressAttributes } from '../../../../openapi/jolokia/queries'; -import { AuthContext } from '../../../../jolokia/customHooks'; +import { AuthContext } from '../../../../jolokia/context'; import { Link } from 'react-router-dom-v5-compat'; export type AddressRowProps = RowProps
& { @@ -19,7 +19,7 @@ export const AddressRow: FC = ({ columns, }) => { const { name } = obj; - const authToken = useContext(AuthContext); + const { token: authToken } = useContext(AuthContext); const { data: routingTypes, isSuccess } = useJolokiaServiceReadAddressAttributes({ jolokiaSessionId: authToken, diff --git a/src/brokers/broker-details/components/JolokiaDevComponents.tsx b/src/brokers/broker-details/components/JolokiaDevComponents.tsx index ef9a1638..80f56d3f 100644 --- a/src/brokers/broker-details/components/JolokiaDevComponents.tsx +++ b/src/brokers/broker-details/components/JolokiaDevComponents.tsx @@ -42,7 +42,7 @@ import { } from '../../../openapi/jolokia/requests'; import { useQuery } from '@tanstack/react-query'; import { Signatures } from '../../../openapi/jolokia/requests/models/Signatures'; -import { AuthContext } from '../../../jolokia/customHooks'; +import { AuthContext } from '../../../jolokia/context'; function getApiHost(): string { return process.env.NODE_ENV === 'production' @@ -69,7 +69,7 @@ export const SignatureSubForm: FC = ({ name, signature, }) => { - const authToken = useContext(AuthContext); + const { token: authToken } = useContext(AuthContext); const [formValues, setFormvalues] = useState>({}); const update = (name: string, value: string) => { const newFormValues = { ...formValues }; @@ -208,7 +208,7 @@ export const FetchAttr: FC = ({ acceptor, queue, }) => { - const authToken = useContext(AuthContext); + const { token: authToken } = useContext(AuthContext); const [formSelectValue, setFormSelectValue] = useState(''); const onChange = (value: string) => { @@ -299,7 +299,7 @@ export const FetchAttr: FC = ({ }; export const JolokiaBrokerDetails: FC = () => { - const authToken = useContext(AuthContext); + const { token: authToken } = useContext(AuthContext); const { data: brokers, isSuccess: brokersSuccess } = useJolokiaServiceGetBrokers({ jolokiaSessionId: authToken }); @@ -327,7 +327,7 @@ export const JolokiaBrokerDetails: FC = () => { }; export const JolokiaAddressDetails: FC = () => { - const authToken = useContext(AuthContext); + const { token: authToken } = useContext(AuthContext); const [selectedAddress, setSelectedAddress] = useState(''); const { data: addresses, isSuccess: addressesSuccess } = @@ -380,7 +380,7 @@ export const JolokiaAddressDetails: FC = () => { }; export const JolokiaAcceptorDetails: FC = () => { - const authToken = useContext(AuthContext); + const { token: authToken } = useContext(AuthContext); const [selectedAcceptor, setSelectedAcceptor] = useState(''); const { data: acceptors, isSuccess: isAcceptorsSuccess } = @@ -433,7 +433,7 @@ export const JolokiaAcceptorDetails: FC = () => { }; export const JolokiaQueueDetails: FC = () => { - const authToken = useContext(AuthContext); + const { token: authToken } = useContext(AuthContext); const [selectedQueue, setSelectesQueue] = useState(''); const { data: queues, isSuccess: isQueueSuccess } = @@ -489,7 +489,7 @@ const JolokiaTestPanel: FC = () => { const [jolokiaTestResult, setJolokiaTestResult] = useState('Result:'); const [requestError, setRequestError] = useState(false); - const authToken = useContext(AuthContext); + const { token: authToken } = useContext(AuthContext); const setError = (error: string) => { setJolokiaTestResult(error); diff --git a/src/jolokia/components/JolokiaAuthentication.tsx b/src/jolokia/components/JolokiaAuthentication.tsx new file mode 100644 index 00000000..2503359e --- /dev/null +++ b/src/jolokia/components/JolokiaAuthentication.tsx @@ -0,0 +1,87 @@ +import { FC, useState } from 'react'; +import { OpenAPI as OpenAPIConfig } from '../../openapi/jolokia/requests/core/OpenAPI'; +import { + useGetApiServerBaseUrl, + useJolokiaLogin, +} from '../../jolokia/customHooks'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { AuthContext } from '../context'; +import { BrokerCR } from '../../k8s/types'; +import { + Button, + Modal, + ModalVariant, + Text, + TextContent, + TextVariants, +} from '@patternfly/react-core'; +import { useTranslation } from '../../i18n/i18n'; + +type JolokiaPropTypes = { + brokerCR: BrokerCR; + podOrdinal: number; +}; + +const Authentication: FC = ({ + children, + brokerCR, + podOrdinal, +}) => { + const jolokiaLogin = useJolokiaLogin(brokerCR, podOrdinal); + const handleModalToggle = () => { + setIsErrorModalOpen(!isErrorModalOpen); + }; + + const handleTryAgain = () => { + setIsErrorModalOpen(false); + window.location.reload(); + }; + const [isErrorModalOpen, setIsErrorModalOpen] = useState(false); + const [hasNotified, setHasNotified] = useState(false); + + if (!hasNotified && jolokiaLogin.isError && jolokiaLogin.source === 'api') { + setIsErrorModalOpen(true); + setHasNotified(true); + } + const { t } = useTranslation(); + return ( + + + {t('try_again')} + , + , + ]} + > + + {t('login_failed_message')} + + + {children} + + ); +}; + +export const JolokiaAuthentication: FC = ({ + children, + brokerCR, + podOrdinal, +}) => { + OpenAPIConfig.BASE = useGetApiServerBaseUrl(); + const querClient = new QueryClient(); + return ( + + + {children} + + + ); +}; diff --git a/src/jolokia/context.ts b/src/jolokia/context.ts new file mode 100644 index 00000000..124a877a --- /dev/null +++ b/src/jolokia/context.ts @@ -0,0 +1,19 @@ +import { createContext } from 'react'; + +export type jolokiaLoginSource = 'api' | 'session'; + +export type JolokiaLogin = { + isSuccess: boolean; + isLoading: boolean; + isError: boolean; + token: string; + source: jolokiaLoginSource; +}; + +export const AuthContext = createContext({ + token: '', + isLoading: true, + isSuccess: false, + isError: false, + source: 'api', +}); diff --git a/src/jolokia/customHooks.ts b/src/jolokia/customHooks.ts index b7498733..6c47e83f 100644 --- a/src/jolokia/customHooks.ts +++ b/src/jolokia/customHooks.ts @@ -7,10 +7,10 @@ import { import { K8sResourceCommon, K8sResourceKind, + useK8sWatchResource, } from '@openshift-console/dynamic-plugin-sdk'; -import { createContext, useState } from 'react'; - -export const AuthContext = createContext(''); +import { useState } from 'react'; +import { JolokiaLogin } from './context'; function getJolokiaProtocol(broker: K8sResourceKind): string { return broker.spec['console'].sslEnabled ? 'https' : 'http'; @@ -112,15 +112,6 @@ const getJolokiaLoginParameters = ( return requestBody; }; -type jolokiaLoginSource = 'api' | 'session'; -type JolokiaLogin = { - isSucces: boolean; - isLoading: boolean; - isError: boolean; - token: string; - source: jolokiaLoginSource; -}; - /** * Use this hook at the top of your first page to get credentials to access the * jolokia api-server. This should be called before any other queries to the @@ -142,10 +133,18 @@ type JolokiaLogin = { */ export const useJolokiaLogin = ( broker: K8sResourceKind, - brokerRoutes: K8sResourceKind[], ordinal: number, ): JolokiaLogin => { - const params = getJolokiaLoginParameters(broker, brokerRoutes, ordinal); + const [routes] = useK8sWatchResource({ + isList: true, + groupVersionKind: { + group: 'route.openshift.io', + kind: 'Route', + version: 'v1', + }, + namespaced: true, + }); + const params = getJolokiaLoginParameters(broker, routes, ordinal); const paramsReady = params.port !== '' && params.jolokiaHost !== '' && @@ -229,7 +228,7 @@ export const useJolokiaLogin = ( // situation depending on the Idle state of the mutation itself. if (isLoginMutationIdle && !needToFetchToken) { return { - isSucces: isSuccessRequestApi, + isSuccess: isSuccessRequestApi, isLoading: isLoadingRequestApi, isError: isErrorRequestApi, token: token, @@ -238,7 +237,7 @@ export const useJolokiaLogin = ( } return { isError: isLoginMutationError, - isSucces: isLoginMutationSuccess, + isSuccess: isLoginMutationSuccess, isLoading: isLoginMutationLoading || isLoginMutationIdle, token: token, source: 'api', diff --git a/src/k8s/customHooks.ts b/src/k8s/customHooks.ts index 4c85a7df..ec231eff 100644 --- a/src/k8s/customHooks.ts +++ b/src/k8s/customHooks.ts @@ -1,7 +1,7 @@ import { useState } from 'react'; -import { Ingress } from './types'; +import { BrokerCR, Ingress } from './types'; import { k8sGet } from '@openshift-console/dynamic-plugin-sdk'; -import { IngressDomainModel } from './models'; +import { AMQBrokerModel, IngressDomainModel } from './models'; export const UseGetIngressDomain = (): { clusterDomain: string; @@ -34,3 +34,34 @@ export const UseGetIngressDomain = (): { return { clusterDomain: domain, isLoading: loading, error: error }; }; + +export const UseGetBrokerCR = ( + brokerName: string, + namespace: string, +): { brokerCr: BrokerCR; isLoading: boolean; error: string } => { + const [brokerDetails, setBrokerDetails] = useState({}); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(''); + + const k8sGetBroker = () => { + setLoading(true); + k8sGet({ model: AMQBrokerModel, name: brokerName, ns: namespace }) + .then((broker: BrokerCR) => { + setBrokerDetails(broker as BrokerCR); + }) + .catch((e) => { + setError(e.message); + }) + .finally(() => { + setLoading(false); + }); + }; + + const [isFirstMount, setIsFirstMount] = useState(true); + if (isFirstMount) { + k8sGetBroker(); + setIsFirstMount(false); + } + + return { brokerCr: brokerDetails, isLoading: loading, error: error }; +};