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 (