diff --git a/web/packages/teleport/src/Discover/Discover.test.tsx b/web/packages/teleport/src/Discover/Discover.test.tsx index 6b60e44d15935..aa8327d5612c0 100644 --- a/web/packages/teleport/src/Discover/Discover.test.tsx +++ b/web/packages/teleport/src/Discover/Discover.test.tsx @@ -25,7 +25,8 @@ import { render, screen } from 'design/utils/testing'; import { Resource } from 'gen-proto-ts/teleport/userpreferences/v1/onboard_pb'; import TeleportContextProvider from 'teleport/TeleportContextProvider'; -import { Discover } from 'teleport/Discover/Discover'; +import { Discover, DiscoverComponent } from 'teleport/Discover/Discover'; +import { ResourceViewConfig } from 'teleport/Discover/flow'; import { FeaturesContextProvider } from 'teleport/FeaturesContext'; import { createTeleportContext, getAcl } from 'teleport/mocks/contexts'; import { getOSSFeatures } from 'teleport/features'; @@ -47,6 +48,9 @@ import { makeTestUserContext } from 'teleport/User/testHelpers/makeTestUserConte import { makeDefaultUserPreferences } from 'teleport/services/userPreferences/userPreferences'; import { ResourceKind } from './Shared'; +import { useDiscover, DiscoverUpdateProps } from './useDiscover'; + +import type { ResourceSpec } from 'teleport/Discover/SelectResource/types'; beforeEach(() => { jest.restoreAllMocks(); @@ -204,3 +208,91 @@ describe('location state', () => { ).not.toBeInTheDocument(); }); }); + +const renderUpdate = (props: DiscoverUpdateProps) => { + const defaultPref = makeDefaultUserPreferences(); + defaultPref.onboard.preferredResources = [Resource.WEB_APPLICATIONS]; + + mockUserContextProviderWith( + makeTestUserContext({ preferences: defaultPref }) + ); + + const userAcl = getAcl(); + const ctx = createTeleportContext({ customAcl: userAcl }); + + const MockComponent1 = () => { + const { agentMeta } = useDiscover(); + return ( + <> + {agentMeta.resourceName === 'saml2' ? agentMeta.resourceName : 'saml1'} + + ); + }; + + const testViews: ResourceViewConfig[] = [ + { + kind: ResourceKind.SamlApplication, + views() { + return [ + { + title: 'MockComponent1', + component: MockComponent1, + }, + ]; + }, + }, + ]; + + return render( + + + + + + ); +}; + +test('update flow: renders single component based on resourceSpec', () => { + const resourceSpec: ResourceSpec = { + name: 'Connect My Computer', + kind: ResourceKind.ConnectMyComputer, + event: null, + icon: 'Laptop', + keywords: '', + hasAccess: true, + }; + + renderUpdate({ resourceSpec: resourceSpec, agentMeta: { resourceName: '' } }); + + expect(screen.queryAllByTestId(ResourceKind.Server).length).toBeFalsy(); + + expect(screen.queryAllByTestId(ResourceKind.Database).length).toBeFalsy(); + + expect(screen.queryAllByTestId(ResourceKind.Application).length).toBeFalsy(); + + expect(screen.queryAllByTestId(ResourceKind.Kubernetes).length).toBeFalsy(); + + expect(screen.getByText('Sign In & Connect My Computer')).toBeInTheDocument(); +}); + +test('update flow: agentMeta is prepopulated based on agentMeta', () => { + const resourceSpec: ResourceSpec = { + name: 'MockComponent1', + kind: ResourceKind.SamlApplication, + event: null, + icon: 'Application', + keywords: '', + hasAccess: true, + }; + + renderUpdate({ + resourceSpec: resourceSpec, + agentMeta: { resourceName: 'saml2' }, + }); + + expect(screen.getByText('saml2')).toBeInTheDocument(); +}); diff --git a/web/packages/teleport/src/Discover/Discover.tsx b/web/packages/teleport/src/Discover/Discover.tsx index 3e56e8dcb72fa..3730f132c282c 100644 --- a/web/packages/teleport/src/Discover/Discover.tsx +++ b/web/packages/teleport/src/Discover/Discover.tsx @@ -29,7 +29,11 @@ import { findViewAtIndex } from 'teleport/components/Wizard/flow'; import { EViewConfigs } from './types'; -import { DiscoverProvider, useDiscover } from './useDiscover'; +import { + DiscoverProvider, + useDiscover, + DiscoverUpdateProps, +} from './useDiscover'; import { DiscoverIcon } from './SelectResource/icons'; function DiscoverContent() { @@ -94,10 +98,17 @@ function DiscoverContent() { ); } -export function DiscoverComponent({ eViewConfigs = [] }: Props) { +export function DiscoverComponent({ + eViewConfigs = [], + updateFlow, +}: DiscoverComponentProps) { const location = useLocation(); return ( - + ); @@ -107,6 +118,7 @@ export function Discover() { return ; } -type Props = { +export type DiscoverComponentProps = { eViewConfigs?: EViewConfigs; + updateFlow?: DiscoverUpdateProps; }; diff --git a/web/packages/teleport/src/Discover/useDiscover.tsx b/web/packages/teleport/src/Discover/useDiscover.tsx index 55b09eaa1cf67..8ab099843af62 100644 --- a/web/packages/teleport/src/Discover/useDiscover.tsx +++ b/web/packages/teleport/src/Discover/useDiscover.tsx @@ -70,6 +70,7 @@ export interface DiscoverContextState { emitErrorEvent(errorStr: string): void; emitEvent(status: DiscoverEventStepStatus, custom?: CustomEventInput): void; eventState: EventState; + isUpdateFlow?: boolean; } type EventState = { @@ -88,11 +89,22 @@ type CustomEventInput = { discoveryConfigMethod?: DiscoverDiscoveryConfigMethod; }; +export type DiscoverUpdateProps = { + // resourceSpecForUpdate specifies ResourceSpec which should be used to + // start a Discover flow. + resourceSpec: ResourceSpec; + // agentMetaForUpdate includes data that will be used to prepopulate input fields + // in the respective Discover compnents. + agentMeta: AgentMeta; +}; + type DiscoverProviderProps = { // mockCtx used for testing purposes. mockCtx?: DiscoverContextState; // Extra view configs that are passed in. This is used to add view configs from Enterprise. eViewConfigs?: EViewConfigs; + // updateFlow holds properties used in Discover update flow. + updateFlow?: DiscoverUpdateProps; }; // DiscoverUrlLocationState define fields to preserve state between @@ -117,6 +129,7 @@ export function DiscoverProvider({ mockCtx, children, eViewConfigs = [], + updateFlow, }: React.PropsWithChildren) { const history = useHistory(); const location = useLocation(); @@ -229,6 +242,14 @@ export function DiscoverProvider({ }); } + // trigger update Discover flow. + useEffect(() => { + if (updateFlow) { + onSelectResource(updateFlow.resourceSpec); + updateAgentMeta(updateFlow.agentMeta); + } + }, [updateFlow]); + // If a location.state.discover was provided, that means the user is // coming back from another location to resume the flow. // Users will resume at the step that is +1 from the step they left from. @@ -453,6 +474,7 @@ export function DiscoverProvider({ emitErrorEvent, emitEvent, eventState, + isUpdateFlow: Boolean(updateFlow), }; return (