import React, { useEffect, useMemo, useRef, useState } from "react"; import { useMount, useUnmount } from "react-use"; import { Table, Thead, Tr, Th, Tbody, Td } from "@patternfly/react-table"; import { EmptyState } from "./empty-state/EmptyState"; import { RemoveSourceAction } from "./actions/RemoveSourceAction"; import { Columns } from "./Columns"; import { DEFAULT_POLLING_DELAY, VALUE_NOT_AVAILABLE } from "./Constants"; import { useDiscoverySources } from "#/migration-wizard/contexts/discovery-sources/Context"; import { Radio, Spinner } from "@patternfly/react-core"; import { Link } from "react-router-dom"; import { Source } from "@migration-planner-ui/api-client/models"; import { AgentStatusView } from "./AgentStatusView"; import { UploadInventoryAction } from "./actions/UploadInventoryAction"; export const SourcesTable: React.FC = () => { const discoverySourcesContext = useDiscoverySources(); const prevSourcesRef = useRef([]); const [isLoading, setIsLoading] = useState(true); const timeoutRef = useRef(null); // Memorize ordered agents const memoizedSources = useMemo(() => { const areSourcesEquals = (prevSources: typeof discoverySourcesContext.sources, newSources: typeof discoverySourcesContext.sources): boolean => { if (!prevSources || !newSources || prevSources.length !== newSources.length) return false; return prevSources.every((agent, index) => agent.id === newSources[index].id); }; if (!areSourcesEquals(prevSourcesRef.current, discoverySourcesContext.sources)) { prevSourcesRef.current = discoverySourcesContext.sources; return discoverySourcesContext.sources ? discoverySourcesContext.sources.sort((a: Source, b: Source) => a.id.localeCompare(b.id)) : []; } return prevSourcesRef.current; }, [discoverySourcesContext]); const [firstSource, ..._otherSources] = memoizedSources ?? []; const hasSources = memoizedSources && memoizedSources.length>0; useMount(async () => { discoverySourcesContext.startPolling(DEFAULT_POLLING_DELAY); if (!discoverySourcesContext.isPolling) { await Promise.all([ discoverySourcesContext.listSources() ]); } }); useUnmount(() => { discoverySourcesContext.stopPolling(); }); useEffect(() => { if (!discoverySourcesContext.sourceSelected && firstSource) { discoverySourcesContext.selectSource(firstSource); } }, [discoverySourcesContext, firstSource, discoverySourcesContext.sourceSelected]); useEffect(() => { // Use timeout to verify memoizedSources variable timeoutRef.current = setTimeout(() => { if (memoizedSources && memoizedSources.length === 0) { setIsLoading(false); } }, 3000); // Timeout in milisecons (3 seconds here) // eslint-disable-next-line @typescript-eslint/explicit-function-return-type return () => { // Clean the timeout in case unmount the component if (timeoutRef.current) { clearTimeout(timeoutRef.current); } }; }, [memoizedSources]); // Show spinner until all data is loaded if ((isLoading && !hasSources) ) { return (
); } else { return (
{memoizedSources && memoizedSources.length>0 && ( )} {memoizedSources && memoizedSources.length>0 ? ( memoizedSources.map((source) => { // Get the agent related to this source const agent = source.agent; return ( ); }) ) : ( )}
{Columns.Name} {Columns.CredentialsUrl} {Columns.Status} {Columns.Hosts} {Columns.VMs} {Columns.Networks} {Columns.Datastores} {Columns.Actions}
discoverySourcesContext.selectSource(source)} /> {agent!==undefined ? ( {agent.credentialUrl} ) : ( '-' ) } {(source?.inventory?.infra.totalHosts ?? VALUE_NOT_AVAILABLE)} {(source?.inventory?.vms.total ?? VALUE_NOT_AVAILABLE)} {(source?.inventory?.infra.networks?.length ?? VALUE_NOT_AVAILABLE)} {(source?.inventory?.infra.datastores?.length ?? VALUE_NOT_AVAILABLE)} {source.name !== "Example" && ( { event.stopPropagation(); await discoverySourcesContext.deleteSource(source.id); event.dismissConfirmationModal(); await Promise.all([ discoverySourcesContext.listSources(), firstSource && discoverySourcesContext.selectSource(firstSource) ]); }} /> )} {!source?.agent && source?.name !== "Example" && ( )}
); } };