diff --git a/web/.storybook/preview.tsx b/web/.storybook/preview.tsx index c31358bef15b8..28661cf7054fb 100644 --- a/web/.storybook/preview.tsx +++ b/web/.storybook/preview.tsx @@ -17,6 +17,7 @@ */ import { Preview } from '@storybook/react'; +import { http, HttpResponse } from 'msw'; import { initialize, mswLoader } from 'msw-storybook-addon'; import { ComponentType, PropsWithChildren } from 'react'; @@ -24,6 +25,7 @@ import Box from '../packages/design/src/Box'; import { bblpTheme, darkTheme, lightTheme } from '../packages/design/src/theme'; import { Theme } from '../packages/design/src/theme/themes/types'; import { ConfiguredThemeProvider } from '../packages/design/src/ThemeProvider'; +import cfg from '../packages/teleport/src/config'; import history from '../packages/teleport/src/services/history/history'; import { UserContextProvider } from '../packages/teleport/src/User'; import Logger, { ConsoleService } from '../packages/teleterm/src/logger'; @@ -33,7 +35,42 @@ import { lightTheme as teletermLightTheme, } from '../packages/teleterm/src/ui/ThemeProvider/theme'; -initialize(); +initialize( + { + onUnhandledRequest(request, print) { + try { + // Ignores asset related http requests, otherwise + // it prints noisy warnings, hiding important ones. + const url = new URL(request.url); + if ( + url.pathname.startsWith('/sb-common-assets') || + url.pathname.startsWith('/index.json') || + url.pathname.startsWith('/.storybook') || + url.pathname.endsWith('.png') || + url.pathname.endsWith('.svg') || + url.pathname.endsWith('.css') || + url.pathname.endsWith('.yaml') + ) { + return; + } + } catch { + /* empty */ + } + + print.warning(); + }, + }, + [ + // we emit these for posthog events (ignores any error), + // and we don't ever mock them in stories. + http.post(cfg.api.captureUserEventPath, () => { + return HttpResponse.json({ message: 'ok' }); + }), + http.post(cfg.api.capturePreUserEventPath, () => { + return HttpResponse.json({ message: 'ok' }); + }), + ] +); history.init(); diff --git a/web/packages/teleport/src/AuthConnectors/AuthConnectorEditor/GitHubConnectorEditor.story.tsx b/web/packages/teleport/src/AuthConnectors/AuthConnectorEditor/GitHubConnectorEditor.story.tsx index 48cc9567656e0..3a8622789b8f1 100644 --- a/web/packages/teleport/src/AuthConnectors/AuthConnectorEditor/GitHubConnectorEditor.story.tsx +++ b/web/packages/teleport/src/AuthConnectors/AuthConnectorEditor/GitHubConnectorEditor.story.tsx @@ -17,11 +17,10 @@ */ import { delay, http, HttpResponse } from 'msw'; -import { MemoryRouter, Route } from 'react-router'; +import { Route } from 'react-router'; -import { ContextProvider } from 'teleport'; import cfg from 'teleport/config'; -import { createTeleportContext } from 'teleport/mocks/contexts'; +import { TeleportProviderBasic } from 'teleport/mocks/providers'; import { connectors } from '../fixtures'; import { GitHubConnectorEditor } from './GitHubConnectorEditor'; @@ -30,52 +29,48 @@ export default { title: 'Teleport/AuthConnectors/GitHubConnectorEditor', }; -export function Processing() { +export function Loaded() { return ( - - - - - - - + + + + ); } -Processing.parameters = { +Loaded.parameters = { msw: { handlers: [ - http.get( - cfg.getGithubConnectorUrl('github_connector'), - async () => await delay('infinite') + http.get(cfg.getGithubConnectorUrl('github_connector'), () => + HttpResponse.json(connectors[0]) ), ], }, }; -export function Loaded() { +export function Processing() { return ( - - - - - - - + + + + ); } -Loaded.parameters = { +Processing.parameters = { msw: { handlers: [ - http.get(cfg.getGithubConnectorUrl('github_connector'), () => - HttpResponse.json(connectors[0]) + http.get( + cfg.getGithubConnectorUrl('github_connector'), + async () => await delay('infinite') ), ], }, @@ -83,17 +78,15 @@ Loaded.parameters = { export function Failed() { return ( - - - - - - - + + + + ); } Failed.parameters = { @@ -110,8 +103,3 @@ Failed.parameters = { ], }, }; - -function ContextWrapper({ children }: { children: JSX.Element }) { - const ctx = createTeleportContext(); - return {children}; -} diff --git a/web/packages/teleport/src/AuthConnectors/AuthConnectors.story.tsx b/web/packages/teleport/src/AuthConnectors/AuthConnectors.story.tsx index 270a2e9168c88..998f3e280ef9d 100644 --- a/web/packages/teleport/src/AuthConnectors/AuthConnectors.story.tsx +++ b/web/packages/teleport/src/AuthConnectors/AuthConnectors.story.tsx @@ -17,11 +17,9 @@ */ import { delay, http, HttpResponse } from 'msw'; -import { MemoryRouter } from 'react-router'; -import { ContextProvider } from 'teleport'; import cfg from 'teleport/config'; -import { createTeleportContext } from 'teleport/mocks/contexts'; +import { TeleportProviderBasic } from 'teleport/mocks/providers'; import { AuthConnectors } from './AuthConnectors'; import { connectors } from './fixtures'; @@ -30,40 +28,36 @@ export default { title: 'Teleport/AuthConnectors', }; -export function Processing() { +export function Loaded() { return ( - - - - - + + + ); } -Processing.parameters = { +Loaded.parameters = { msw: { handlers: [ - http.get( - cfg.getGithubConnectorsUrl(), - async () => await delay('infinite') + http.get(cfg.getGithubConnectorsUrl(), () => + HttpResponse.json({ connectors: [connectors[0], connectors[1]] }) ), ], }, }; -export function Loaded() { +export function Processing() { return ( - - - - - + + + ); } -Loaded.parameters = { +Processing.parameters = { msw: { handlers: [ - http.get(cfg.getGithubConnectorsUrl(), () => - HttpResponse.json([connectors[0], connectors[1]]) + http.get( + cfg.getGithubConnectorsUrl(), + async () => await delay('infinite') ), ], }, @@ -71,28 +65,24 @@ Loaded.parameters = { export function Empty() { return ( - - - - - + + + ); } Empty.parameters = { msw: { handlers: [ - http.get(cfg.getGithubConnectorsUrl(), () => HttpResponse.json([])), + http.get(cfg.getGithubConnectorsUrl(), () => HttpResponse.json({})), ], }, }; export function Failed() { return ( - - - - - + + + ); } Failed.parameters = { @@ -109,8 +99,3 @@ Failed.parameters = { ], }, }; - -function ContextWrapper({ children }: { children: JSX.Element }) { - const ctx = createTeleportContext(); - return {children}; -} diff --git a/web/packages/teleport/src/Bots/Add/AddBotsPicker.story.tsx b/web/packages/teleport/src/Bots/Add/AddBotsPicker.story.tsx index 0922a537bcb22..416f466ccf8f0 100644 --- a/web/packages/teleport/src/Bots/Add/AddBotsPicker.story.tsx +++ b/web/packages/teleport/src/Bots/Add/AddBotsPicker.story.tsx @@ -16,10 +16,7 @@ * along with this program. If not, see . */ -import { MemoryRouter } from 'react-router'; - -import { ContextProvider } from 'teleport'; -import { createTeleportContext } from 'teleport/mocks/contexts'; +import { TeleportProviderBasic } from 'teleport/mocks/providers'; import { AddBotsPicker } from './AddBotsPicker'; @@ -27,14 +24,8 @@ export default { title: 'Teleport/Bots/Add/AddBotsPicker', }; -export const Picker = () => { - const ctx = createTeleportContext(); - - return ( - - - - - - ); -}; +export const Picker = () => ( + + + +); diff --git a/web/packages/teleport/src/Discover/AwsMangementConsole/CreateAppAccess/CreateAppAccess.story.tsx b/web/packages/teleport/src/Discover/AwsMangementConsole/CreateAppAccess/CreateAppAccess.story.tsx index 32fd381b83658..750dc61dc4054 100644 --- a/web/packages/teleport/src/Discover/AwsMangementConsole/CreateAppAccess/CreateAppAccess.story.tsx +++ b/web/packages/teleport/src/Discover/AwsMangementConsole/CreateAppAccess/CreateAppAccess.story.tsx @@ -17,23 +17,19 @@ */ import { delay, http, HttpResponse } from 'msw'; -import { MemoryRouter } from 'react-router'; import { Info } from 'design/Alert'; -import { ContextProvider } from 'teleport'; import cfg from 'teleport/config'; -import { ResourceKind } from 'teleport/Discover/Shared'; import { - DiscoverContextState, - DiscoverProvider, -} from 'teleport/Discover/useDiscover'; -import { createTeleportContext } from 'teleport/mocks/contexts'; + RequiredDiscoverProviders, + resourceSpecAppAwsCliConsole, +} from 'teleport/Discover/Fixtures/fixtures'; +import { AgentMeta } from 'teleport/Discover/useDiscover'; import { IntegrationKind, IntegrationStatusCode, } from 'teleport/services/integrations'; -import { DiscoverEventResource } from 'teleport/services/userEvent'; import { CreateAppAccess } from './CreateAppAccess'; @@ -84,60 +80,29 @@ Failed.parameters = { }; const Component = () => { - const ctx = createTeleportContext(); - const discoverCtx: DiscoverContextState = { - agentMeta: { - resourceName: 'aws-console', - agentMatcherLabels: [], - awsIntegration: { - kind: IntegrationKind.AwsOidc, - name: 'some-oidc-name', - resourceType: 'integration', - spec: { - roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', - issuerS3Bucket: '', - issuerS3Prefix: '', - }, - statusCode: IntegrationStatusCode.Running, + const agentMeta: AgentMeta = { + resourceName: 'aws-console', + agentMatcherLabels: [], + awsIntegration: { + kind: IntegrationKind.AwsOidc, + name: 'some-oidc-name', + resourceType: 'integration', + spec: { + roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', + issuerS3Bucket: '', + issuerS3Prefix: '', }, + statusCode: IntegrationStatusCode.Running, }, - currentStep: 0, - nextStep: () => null, - prevStep: () => null, - onSelectResource: () => null, - resourceSpec: { - name: '', - kind: ResourceKind.Application, - icon: null, - keywords: [], - event: DiscoverEventResource.ApplicationHttp, - appMeta: { - awsConsole: true, - }, - }, - exitFlow: () => null, - viewConfig: null, - indexedViews: [], - setResourceSpec: () => null, - updateAgentMeta: () => null, - emitErrorEvent: () => null, - emitEvent: () => null, - eventState: null, }; - cfg.proxyCluster = 'localhost'; return ( - - - - Devs: Click next to see next state - - - - + Devs: Click next to see next state + + ); }; diff --git a/web/packages/teleport/src/Discover/AwsMangementConsole/CreateAppAccess/CreateAppAccess.test.tsx b/web/packages/teleport/src/Discover/AwsMangementConsole/CreateAppAccess/CreateAppAccess.test.tsx index 89a5ef1abcd3d..18a2df0c442fd 100644 --- a/web/packages/teleport/src/Discover/AwsMangementConsole/CreateAppAccess/CreateAppAccess.test.tsx +++ b/web/packages/teleport/src/Discover/AwsMangementConsole/CreateAppAccess/CreateAppAccess.test.tsx @@ -16,35 +16,28 @@ * along with this program. If not, see . */ -import { MemoryRouter } from 'react-router'; - import { render, screen, userEvent } from 'design/utils/testing'; -import { ContextProvider } from 'teleport'; -import cfg from 'teleport/config'; import { app } from 'teleport/Discover/AwsMangementConsole/fixtures'; -import { ResourceKind } from 'teleport/Discover/Shared'; import { - DiscoverContextState, - DiscoverProvider, -} from 'teleport/Discover/useDiscover'; -import { FeaturesContextProvider } from 'teleport/FeaturesContext'; -import { createTeleportContext } from 'teleport/mocks/contexts'; + RequiredDiscoverProviders, + resourceSpecAppAwsCliConsole, +} from 'teleport/Discover/Fixtures/fixtures'; +import { AgentMeta } from 'teleport/Discover/useDiscover'; import { IntegrationKind, integrationService, IntegrationStatusCode, } from 'teleport/services/integrations'; -import { - DiscoverEventResource, - userEventService, -} from 'teleport/services/userEvent'; +import { userEventService } from 'teleport/services/userEvent'; import { ProxyRequiresUpgrade } from 'teleport/services/version/unsupported'; -import TeleportContext from 'teleport/teleportContext'; import { CreateAppAccess } from './CreateAppAccess'; beforeEach(() => { + jest + .spyOn(userEventService, 'captureDiscoverEvent') + .mockResolvedValue(undefined as never); jest.spyOn(integrationService, 'createAwsAppAccessV2').mockResolvedValue(app); jest .spyOn(userEventService, 'captureDiscoverEvent') @@ -58,9 +51,7 @@ afterEach(() => { test('create app access', async () => { jest.spyOn(integrationService, 'createAwsAppAccess').mockResolvedValue(app); - const { ctx, discoverCtx } = getMockedContexts(); - - renderCreateAppAccess(ctx, discoverCtx); + renderCreateAppAccess(); await screen.findByText(/bash/i); await userEvent.click(screen.getByRole('button', { name: /next/i })); @@ -75,9 +66,7 @@ test('create app access with v1 endpoint auto retry', async () => { .mockRejectedValueOnce(new Error(ProxyRequiresUpgrade)); jest.spyOn(integrationService, 'createAwsAppAccess').mockResolvedValue(app); - const { ctx, discoverCtx } = getMockedContexts(); - - renderCreateAppAccess(ctx, discoverCtx); + renderCreateAppAccess(); await screen.findByText(/bash/i); await userEvent.click(screen.getByRole('button', { name: /next/i })); @@ -87,70 +76,29 @@ test('create app access with v1 endpoint auto retry', async () => { expect(integrationService.createAwsAppAccess).toHaveBeenCalledTimes(1); }); -function getMockedContexts() { - const ctx = createTeleportContext(); - const discoverCtx: DiscoverContextState = { - agentMeta: { - resourceName: 'aws-console', - agentMatcherLabels: [], - awsIntegration: { - kind: IntegrationKind.AwsOidc, - name: 'some-oidc-name', - resourceType: 'integration', - spec: { - roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', - issuerS3Bucket: '', - issuerS3Prefix: '', - }, - statusCode: IntegrationStatusCode.Running, - }, +const agentMeta: AgentMeta = { + resourceName: 'aws-console', + agentMatcherLabels: [], + awsIntegration: { + kind: IntegrationKind.AwsOidc, + name: 'some-oidc-name', + resourceType: 'integration', + spec: { + roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', + issuerS3Bucket: '', + issuerS3Prefix: '', }, - currentStep: 0, - nextStep: jest.fn(), - prevStep: () => null, - onSelectResource: () => null, - resourceSpec: { - kind: ResourceKind.Application, - appMeta: { awsConsole: true }, - name: '', - icon: undefined, - keywords: [], - event: DiscoverEventResource.ApplicationHttp, - }, - exitFlow: () => null, - viewConfig: null, - indexedViews: [], - setResourceSpec: () => null, - updateAgentMeta: () => null, - emitErrorEvent: () => null, - emitEvent: jest.fn(), - eventState: null, - }; - - jest - .spyOn(userEventService, 'captureDiscoverEvent') - .mockResolvedValue(undefined as never); - - return { ctx, discoverCtx }; -} + statusCode: IntegrationStatusCode.Running, + }, +}; -function renderCreateAppAccess( - ctx: TeleportContext, - discoverCtx: DiscoverContextState -) { +function renderCreateAppAccess() { return render( - - - - - - - - - + + ); } diff --git a/web/packages/teleport/src/Discover/AwsMangementConsole/CreateAppAccess/CreateAppAccess.tsx b/web/packages/teleport/src/Discover/AwsMangementConsole/CreateAppAccess/CreateAppAccess.tsx index 18391957d0a07..14ad8555dbfb5 100644 --- a/web/packages/teleport/src/Discover/AwsMangementConsole/CreateAppAccess/CreateAppAccess.tsx +++ b/web/packages/teleport/src/Discover/AwsMangementConsole/CreateAppAccess/CreateAppAccess.tsx @@ -101,7 +101,7 @@ export function CreateAppAccess() { return ( {({ validator }) => ( - + <>
Enable Access to AWS with Teleport Application Access

An application will be created that will use the selected AWS OIDC @@ -172,7 +172,7 @@ export function CreateAppAccess() { appName={agentMeta.resourceName} /> )} - + )} ); diff --git a/web/packages/teleport/src/Discover/AwsMangementConsole/SetupAccess/SetupAccess.story.tsx b/web/packages/teleport/src/Discover/AwsMangementConsole/SetupAccess/SetupAccess.story.tsx index 61d0c1ee65f48..ca6f976394fe1 100644 --- a/web/packages/teleport/src/Discover/AwsMangementConsole/SetupAccess/SetupAccess.story.tsx +++ b/web/packages/teleport/src/Discover/AwsMangementConsole/SetupAccess/SetupAccess.story.tsx @@ -22,19 +22,16 @@ import { MemoryRouter } from 'react-router'; import { AwsRole } from 'shared/services/apps'; -import { ContextProvider } from 'teleport'; import cfg from 'teleport/config'; -import { ResourceKind } from 'teleport/Discover/Shared'; import { - DiscoverContextState, - DiscoverProvider, -} from 'teleport/Discover/useDiscover'; -import { createTeleportContext, getAcl } from 'teleport/mocks/contexts'; + RequiredDiscoverProviders, + resourceSpecAppAwsCliConsole, +} from 'teleport/Discover/Fixtures/fixtures'; +import { getAcl } from 'teleport/mocks/contexts'; import { IntegrationKind, IntegrationStatusCode, } from 'teleport/services/integrations'; -import { DiscoverEventResource } from 'teleport/services/userEvent'; import { app } from '../fixtures'; import { SetupAccess } from './SetupAccess'; @@ -147,62 +144,30 @@ const Provider = ({ noAccess?: boolean; isSso?: boolean; }) => { - const ctx = createTeleportContext(); - if (noAccess) { - ctx.storeUser.state.acl = getAcl({ noAccess: true }); - } - if (isSso) { - ctx.storeUser.state.authType = 'sso'; - } - const discoverCtx: DiscoverContextState = { - prevStep: () => {}, - nextStep: () => {}, - agentMeta: { - app: { - ...app, - awsRoles, - }, - awsIntegration: { - resourceType: 'integration', - kind: IntegrationKind.AwsOidc, - name: 'some-aws-oidc-name', - statusCode: IntegrationStatusCode.Running, - spec: { - roleArn: 'arn:aws:iam::123456789012:role/some-iam-role-name', - issuerS3Bucket: '', - issuerS3Prefix: '', - }, - }, - }, - currentStep: 0, - onSelectResource: () => null, - resourceSpec: { - kind: ResourceKind.Application, - appMeta: { awsConsole: true }, - name: '', - icon: undefined, - keywords: [], - event: DiscoverEventResource.ApplicationHttp, - }, - exitFlow: () => null, - viewConfig: null, - indexedViews: [], - setResourceSpec: () => null, - updateAgentMeta: () => null, - emitErrorEvent: () => null, - emitEvent: () => null, - eventState: null, - }; - return ( - - - {children} - - + {children} + ); }; diff --git a/web/packages/teleport/src/Discover/AwsMangementConsole/TestConnection/TestConnection.story.tsx b/web/packages/teleport/src/Discover/AwsMangementConsole/TestConnection/TestConnection.story.tsx index 151eafda5d200..be832bea3f5a0 100644 --- a/web/packages/teleport/src/Discover/AwsMangementConsole/TestConnection/TestConnection.story.tsx +++ b/web/packages/teleport/src/Discover/AwsMangementConsole/TestConnection/TestConnection.story.tsx @@ -16,15 +16,10 @@ * along with this program. If not, see . */ -import { MemoryRouter } from 'react-router'; - -import { ContextProvider } from 'teleport'; -import cfg from 'teleport/config'; import { - DiscoverContextState, - DiscoverProvider, -} from 'teleport/Discover/useDiscover'; -import { createTeleportContext } from 'teleport/mocks/contexts'; + RequiredDiscoverProviders, + resourceSpecAppAwsCliConsole, +} from 'teleport/Discover/Fixtures/fixtures'; import { app } from '../fixtures'; import { TestConnection as Comp } from './TestConnection'; @@ -40,51 +35,30 @@ export const TestConnection = () => ( ); const Provider = ({ children }) => { - const ctx = createTeleportContext(); - const discoverCtx: DiscoverContextState = { - prevStep: () => {}, - nextStep: () => {}, - agentMeta: { - app: { - ...app, - awsRoles: [ - { - name: 'static-arn1', - arn: 'arn:aws:iam::123456789012:role/static-arn1', - display: 'static-arn1', - accountId: '123456789012', - }, - { - name: 'static-arn2', - arn: 'arn:aws:iam::123456789012:role/static-arn2', - display: 'static-arn2', - accountId: '123456789012', - }, - ], - }, - }, - currentStep: 0, - onSelectResource: () => null, - resourceSpec: undefined, - exitFlow: () => null, - viewConfig: null, - indexedViews: [], - setResourceSpec: () => null, - updateAgentMeta: () => null, - emitErrorEvent: () => null, - emitEvent: () => null, - eventState: null, - }; - return ( - - - {children} - - + {children} + ); }; diff --git a/web/packages/teleport/src/Discover/AwsMangementConsole/TestConnection/TestConnection.tsx b/web/packages/teleport/src/Discover/AwsMangementConsole/TestConnection/TestConnection.tsx index 7ebae176c4324..3d3ba87739010 100644 --- a/web/packages/teleport/src/Discover/AwsMangementConsole/TestConnection/TestConnection.tsx +++ b/web/packages/teleport/src/Discover/AwsMangementConsole/TestConnection/TestConnection.tsx @@ -19,7 +19,7 @@ import { useState } from 'react'; import { Box, H3, Link, Mark } from 'design'; -import { OutlineInfo } from 'design/Alert/Alert'; +import { Info } from 'design/Alert/Alert'; import { P } from 'design/Text/Text'; import Select, { type Option } from 'shared/components/Select'; import { TextSelectCopy } from 'shared/components/TextSelectCopy'; @@ -108,17 +108,17 @@ export function TestConnection() {

Connect to your application:

- +

- If the connection can't be established, ensure the IAM role you are - trying to assume is{' '} + If the connection can't be established, ensure the IAM role you + are trying to assume is{' '} tagged {' '} with key teleport.dev/integration and value{' '} true.

-
+
diff --git a/web/packages/teleport/src/Discover/ConnectMyComputer/SetupConnect/SetupConnect.story.tsx b/web/packages/teleport/src/Discover/ConnectMyComputer/SetupConnect/SetupConnect.story.tsx index c7dd146c15c6c..41f7eedbe1127 100644 --- a/web/packages/teleport/src/Discover/ConnectMyComputer/SetupConnect/SetupConnect.story.tsx +++ b/web/packages/teleport/src/Discover/ConnectMyComputer/SetupConnect/SetupConnect.story.tsx @@ -27,6 +27,7 @@ import { import { ContextProvider } from 'teleport'; import cfg from 'teleport/config'; +import { DiscoverBox } from 'teleport/Discover/Shared'; import { createTeleportContext } from 'teleport/mocks/contexts'; import { makeDefaultUserPreferences } from 'teleport/services/userPreferences/userPreferences'; import { UserContext } from 'teleport/User/UserContext'; @@ -157,7 +158,9 @@ const Provider = ({ children }) => { updateDiscoverResourcePreferences, }} > - {children} + + {children} + ); diff --git a/web/packages/teleport/src/Discover/ConnectMyComputer/SetupConnect/SetupConnect.tsx b/web/packages/teleport/src/Discover/ConnectMyComputer/SetupConnect/SetupConnect.tsx index f40940df7820e..7400eba823106 100644 --- a/web/packages/teleport/src/Discover/ConnectMyComputer/SetupConnect/SetupConnect.tsx +++ b/web/packages/teleport/src/Discover/ConnectMyComputer/SetupConnect/SetupConnect.tsx @@ -154,17 +154,14 @@ export function SetupConnect( ); pollingStatus = ( - // Override max-width to match StyledBox's max-width. - - - We're still looking for your computer - - + + We're still looking for your computer + ); } else if (node) { pollingStatus = ( @@ -223,7 +220,7 @@ export function SetupConnect( - {pollingStatus} + {pollingStatus} { - const ctx = createTeleportContext(); - const discoverCtx: DiscoverContextState = { - ...agentStepProps, - currentStep: 0, - onSelectResource: () => null, - resourceSpec: undefined, - exitFlow: () => null, - viewConfig: null, - indexedViews: [], - setResourceSpec: () => null, - updateAgentMeta: () => null, - emitErrorEvent: () => null, - emitEvent: () => null, - eventState: null, - }; - return ( - - - {children} - - + {children} + ); }; diff --git a/web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabase.story.tsx b/web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabase.story.tsx index c34bee1ab3a28..35dac2b532e9f 100644 --- a/web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabase.story.tsx +++ b/web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabase.story.tsx @@ -18,6 +18,8 @@ import { MemoryRouter } from 'react-router'; +import { DiscoverBox } from 'teleport/Discover/Shared'; + import { DatabaseEngine, DatabaseLocation } from '../../SelectResource'; import { CreateDatabaseView } from './CreateDatabase'; import type { State } from './useCreateDatabase'; @@ -28,38 +30,48 @@ export default { export const InitSelfHostedPostgres = () => ( - + + + ); export const InitSelfHostedMySql = () => ( - + + + ); export const NoPerm = () => ( - + + + ); export const Processing = () => ( - + + + ); export const Failed = () => ( - + + + ); diff --git a/web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabase.tsx b/web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabase.tsx index 79bceda4fcae4..fd55d5cbc33cf 100644 --- a/web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabase.tsx +++ b/web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabase.tsx @@ -103,7 +103,7 @@ export function CreateDatabaseView({ return ( {({ validator }) => ( - + <>
Register a Database
Create a new database resource for the database server. @@ -204,7 +204,7 @@ export function CreateDatabaseView({ next={nextStep} /> )} -
+ )}
); diff --git a/web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabaseDialog.tsx b/web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabaseDialog.tsx index 47deff24e7b52..490a482901c33 100644 --- a/web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabaseDialog.tsx +++ b/web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabaseDialog.tsx @@ -143,7 +143,7 @@ const SuccessContent = ({ dbName, onClick }) => ( <> - Database "{dbName}" successfully registered + Database "{dbName}" successfully registered Next diff --git a/web/packages/teleport/src/Discover/Database/CreateDatabase/useCreateDatabase.test.tsx b/web/packages/teleport/src/Discover/Database/CreateDatabase/useCreateDatabase.test.tsx index 4ee174f0486d7..a9315bfd212c8 100644 --- a/web/packages/teleport/src/Discover/Database/CreateDatabase/useCreateDatabase.test.tsx +++ b/web/packages/teleport/src/Discover/Database/CreateDatabase/useCreateDatabase.test.tsx @@ -17,19 +17,11 @@ */ import { act, renderHook, waitFor } from '@testing-library/react'; -import { MemoryRouter } from 'react-router'; -import { ContextProvider } from 'teleport'; import cfg from 'teleport/config'; -import { - DatabaseEngine, - DatabaseLocation, -} from 'teleport/Discover/SelectResource'; -import { - DiscoverContextState, - DiscoverProvider, -} from 'teleport/Discover/useDiscover'; -import { FeaturesContextProvider } from 'teleport/FeaturesContext'; +import { resourceSpecAwsRdsAuroraMysql } from 'teleport/Discover/Fixtures/databases'; +import { RequiredDiscoverProviders } from 'teleport/Discover/Fixtures/fixtures'; +import { DiscoverContextState } from 'teleport/Discover/useDiscover'; import { createTeleportContext } from 'teleport/mocks/contexts'; import api from 'teleport/services/api'; import { @@ -257,12 +249,7 @@ describe('registering new databases, mainly error checking', () => { nextStep: jest.fn(x => x), prevStep: () => null, onSelectResource: () => null, - resourceSpec: { - dbMeta: { - location: DatabaseLocation.Aws, - engine: DatabaseEngine.AuroraMysql, - }, - } as any, + resourceSpec: resourceSpecAwsRdsAuroraMysql, exitFlow: () => null, viewConfig: null, indexedViews: [], @@ -297,19 +284,14 @@ describe('registering new databases, mainly error checking', () => { .mockResolvedValue({ services }); wrapper = ({ children }) => ( - - - - - {children} - - - - + {children} + ); }); diff --git a/web/packages/teleport/src/Discover/Database/DeployService/AutoDeploy/AutoDeploy.story.tsx b/web/packages/teleport/src/Discover/Database/DeployService/AutoDeploy/AutoDeploy.story.tsx index 11f103e8744dc..c1463032de9b8 100644 --- a/web/packages/teleport/src/Discover/Database/DeployService/AutoDeploy/AutoDeploy.story.tsx +++ b/web/packages/teleport/src/Discover/Database/DeployService/AutoDeploy/AutoDeploy.story.tsx @@ -17,19 +17,19 @@ */ import { delay, http, HttpResponse } from 'msw'; +import { PropsWithChildren } from 'react'; + +import { Info } from 'design/Alert'; import cfg from 'teleport/config'; import { - ComponentWrapper, - getDbMeta, - getDbResourceSpec, + getSelectedAwsPostgresDbMeta, + resourceSpecAwsRdsMySql, + resourceSpecAwsRdsPostgres, } from 'teleport/Discover/Fixtures/databases'; -import { TeleportProvider } from 'teleport/Discover/Fixtures/fixtures'; -import { - DatabaseEngine, - DatabaseLocation, -} from 'teleport/Discover/SelectResource'; -import { ResourceKind } from 'teleport/Discover/Shared'; +import { RequiredDiscoverProviders } from 'teleport/Discover/Fixtures/fixtures'; +import { SelectResourceSpec } from 'teleport/Discover/SelectResource/resources'; +import { DbMeta } from 'teleport/Discover/useDiscover'; import { AutoDeploy } from './AutoDeploy'; @@ -39,9 +39,9 @@ export default { export const Init = () => { return ( - + - + ); }; Init.parameters = { @@ -61,24 +61,25 @@ Init.parameters = { }; export const InitWithAutoDiscover = () => { - const dbMeta = getDbMeta(); + const dbMeta = getSelectedAwsPostgresDbMeta(); dbMeta.selectedAwsRdsDb = undefined; // there is no selection for discovery return ( - + + Devs: difference is that there should be no offer to manually install + service + + - + ); }; InitWithAutoDiscover.parameters = { @@ -101,22 +102,19 @@ InitWithAutoDiscover.parameters = { export const InitWithLabelsWithDeployFailure = () => { return ( - + Devs: Click "deploy..." to see next state - + ); }; InitWithLabelsWithDeployFailure.parameters = { @@ -140,15 +138,15 @@ InitWithLabelsWithDeployFailure.parameters = { }, }; -export const InitSecurityGroupsLoadingFailed = () => { +export const InitSgSubnetLoadingFailed = () => { return ( - + - + ); }; -InitSecurityGroupsLoadingFailed.parameters = { +InitSgSubnetLoadingFailed.parameters = { msw: { handlers: [ http.post(cfg.api.awsSecurityGroupsListPath, () => @@ -171,15 +169,15 @@ InitSecurityGroupsLoadingFailed.parameters = { }, }; -export const InitSecurityGroupsLoading = () => { +export const InitSgSubnetLoading = () => { return ( - + - + ); }; -InitSecurityGroupsLoading.parameters = { +InitSgSubnetLoading.parameters = { msw: { handlers: [ http.post(cfg.api.awsSecurityGroupsListPath, () => delay('infinite')), @@ -417,3 +415,14 @@ const securityGroupsResponse = [ ], }, ]; + +const DiscoverProviderDatabase: React.FC< + PropsWithChildren<{ resourceSpec?: SelectResourceSpec; dbMeta?: DbMeta }> +> = ({ children, resourceSpec, dbMeta }) => ( + + {children} + +); diff --git a/web/packages/teleport/src/Discover/Database/DeployService/AutoDeploy/AutoDeploy.test.tsx b/web/packages/teleport/src/Discover/Database/DeployService/AutoDeploy/AutoDeploy.test.tsx index f45dabc1a477b..c8494133f23de 100644 --- a/web/packages/teleport/src/Discover/Database/DeployService/AutoDeploy/AutoDeploy.test.tsx +++ b/web/packages/teleport/src/Discover/Database/DeployService/AutoDeploy/AutoDeploy.test.tsx @@ -16,25 +16,12 @@ * along with this program. If not, see . */ -import { MemoryRouter } from 'react-router'; - import { act, fireEvent, render, screen } from 'design/utils/testing'; -import { ContextProvider } from 'teleport'; -import cfg from 'teleport/config'; -import { - DatabaseEngine, - DatabaseLocation, -} from 'teleport/Discover/SelectResource'; -import { ResourceKind } from 'teleport/Discover/Shared'; -import { PingTeleportProvider } from 'teleport/Discover/Shared/PingTeleportContext'; +import { resourceSpecAwsRdsAuroraMysql } from 'teleport/Discover/Fixtures/databases'; +import { RequiredDiscoverProviders } from 'teleport/Discover/Fixtures/fixtures'; import { SHOW_HINT_TIMEOUT } from 'teleport/Discover/Shared/useShowHint'; -import { - DbMeta, - DiscoverContextState, - DiscoverProvider, -} from 'teleport/Discover/useDiscover'; -import { FeaturesContextProvider } from 'teleport/FeaturesContext'; +import { AgentMeta } from 'teleport/Discover/useDiscover'; import { createTeleportContext } from 'teleport/mocks/contexts'; import { AwsRdsDatabase, @@ -85,6 +72,14 @@ describe('test AutoDeploy.tsx', () => { jest.useFakeTimers(); beforeEach(() => { + jest + .spyOn(integrationService, 'deployDatabaseServices') + .mockResolvedValue('dashboard-url'); + + jest + .spyOn(userEventService, 'captureDiscoverEvent') + .mockResolvedValue(undefined as never); + jest.spyOn(integrationService, 'fetchAwsSubnets').mockResolvedValue({ nextToken: '', subnets: [ @@ -119,9 +114,9 @@ describe('test AutoDeploy.tsx', () => { } test('clicking button renders command', async () => { - const { teleCtx, discoverCtx } = getMockedContexts(); + const { teleCtx } = getMockedContexts(); - renderAutoDeploy(teleCtx, discoverCtx); + renderAutoDeploy(teleCtx); await waitForSubnetsAndSecurityGroups(); fireEvent.click(screen.getByText(/generate command/i)); @@ -135,9 +130,9 @@ describe('test AutoDeploy.tsx', () => { }); test('invalid role name', async () => { - const { teleCtx, discoverCtx } = getMockedContexts(); + const { teleCtx } = getMockedContexts(); - renderAutoDeploy(teleCtx, discoverCtx); + renderAutoDeploy(teleCtx); await waitForSubnetsAndSecurityGroups(); expect( @@ -159,9 +154,9 @@ describe('test AutoDeploy.tsx', () => { }); test('deploy hint states', async () => { - const { teleCtx, discoverCtx } = getMockedContexts(); + const { teleCtx } = getMockedContexts(); - renderAutoDeploy(teleCtx, discoverCtx); + renderAutoDeploy(teleCtx); await waitForSubnetsAndSecurityGroups(); fireEvent.click(screen.getByText(/Deploy Teleport Service/i)); @@ -207,74 +202,33 @@ describe('test AutoDeploy.tsx', () => { }); const TEST_PING_INTERVAL = 1000 * 60 * 5; // 5 minutes +const agentMeta: AgentMeta = { + resourceName: 'db1', + awsRegion: region, + awsIntegration: mockIntegration, + selectedAwsRdsDb: mockAwsRdsDb, + agentMatcherLabels: mockDbLabels, +}; function getMockedContexts() { const teleCtx = createTeleportContext(); - const discoverCtx: DiscoverContextState = { - agentMeta: { - resourceName: 'db1', - awsRegion: region, - awsIntegration: mockIntegration, - selectedAwsRdsDb: mockAwsRdsDb, - agentMatcherLabels: mockDbLabels, - } as DbMeta, - currentStep: 0, - nextStep: jest.fn(x => x), - prevStep: () => null, - onSelectResource: () => null, - resourceSpec: { - dbMeta: { - location: DatabaseLocation.Aws, - engine: DatabaseEngine.AuroraMysql, - }, - } as any, - viewConfig: null, - exitFlow: null, - indexedViews: [], - setResourceSpec: () => null, - updateAgentMeta: jest.fn(x => x), - emitErrorEvent: () => null, - emitEvent: () => null, - eventState: null, - }; - - jest - .spyOn(integrationService, 'deployDatabaseServices') - .mockResolvedValue('dashboard-url'); jest.spyOn(teleCtx.databaseService, 'fetchDatabases').mockResolvedValue({ agents: [], }); - jest - .spyOn(userEventService, 'captureDiscoverEvent') - .mockResolvedValue(undefined as never); - - return { teleCtx, discoverCtx }; + return { teleCtx }; } -function renderAutoDeploy( - ctx: TeleportContext, - discoverCtx: DiscoverContextState -) { +function renderAutoDeploy(ctx: TeleportContext) { return render( - - - - - - - - - - - + + ); } diff --git a/web/packages/teleport/src/Discover/Database/DeployService/AutoDeploy/AutoDeploy.tsx b/web/packages/teleport/src/Discover/Database/DeployService/AutoDeploy/AutoDeploy.tsx index 0824ffb2ad9ca..94be9f8757d69 100644 --- a/web/packages/teleport/src/Discover/Database/DeployService/AutoDeploy/AutoDeploy.tsx +++ b/web/packages/teleport/src/Discover/Database/DeployService/AutoDeploy/AutoDeploy.tsx @@ -17,7 +17,7 @@ */ import { useEffect, useState } from 'react'; -import styled, { useTheme } from 'styled-components'; +import { useTheme } from 'styled-components'; import { Alert, @@ -56,6 +56,7 @@ import { AlternateInstructionButton, Header, HeaderSubtitle, + StyledBox, TextIcon, useShowHint, } from '../../../Shared'; @@ -608,13 +609,6 @@ export function AutoDiscoverDeploySuccess({ ); } -const StyledBox = styled(Box)` - max-width: 1000px; - background-color: ${props => props.theme.colors.spotBackground[0]}; - padding: ${props => `${props.theme.space[3]}px`}; - border-radius: ${props => `${props.theme.space[2]}px`}; -`; - const AlertIcon = () => ( ); diff --git a/web/packages/teleport/src/Discover/Database/DeployService/ManualDeploy/ManualDeploy.story.tsx b/web/packages/teleport/src/Discover/Database/DeployService/ManualDeploy/ManualDeploy.story.tsx index 6cbf302b8b66c..6a9d91a704eca 100644 --- a/web/packages/teleport/src/Discover/Database/DeployService/ManualDeploy/ManualDeploy.story.tsx +++ b/web/packages/teleport/src/Discover/Database/DeployService/ManualDeploy/ManualDeploy.story.tsx @@ -17,28 +17,14 @@ */ import { http, HttpResponse } from 'msw'; -import { MemoryRouter } from 'react-router'; -import { ContextProvider, Context as TeleportContext } from 'teleport'; import cfg from 'teleport/config'; -import { - DatabaseEngine, - DatabaseLocation, -} from 'teleport/Discover/SelectResource'; -import { ResourceKind } from 'teleport/Discover/Shared'; -import { PingTeleportProvider } from 'teleport/Discover/Shared/PingTeleportContext'; -import { - DiscoverContextState, - DiscoverProvider, -} from 'teleport/Discover/useDiscover'; -import { FeaturesContextProvider } from 'teleport/FeaturesContext'; -import { getUserContext } from 'teleport/mocks/contexts'; +import { resourceSpecAwsRdsPostgres } from 'teleport/Discover/Fixtures/databases'; +import { RequiredDiscoverProviders } from 'teleport/Discover/Fixtures/fixtures'; import { INTERNAL_RESOURCE_ID_LABEL_KEY } from 'teleport/services/joinToken'; import ManualDeploy from './ManualDeploy'; -const DEFAULT_PING_INTERVAL = 1000 * 100; // 100 seconds - export default { title: 'Teleport/Discover/Database/Deploy/Manual', }; @@ -78,73 +64,29 @@ InitWithLabels.parameters = { msw: { handlers: [ http.post(cfg.api.discoveryJoinToken.createV2, () => - HttpResponse.json({}) + HttpResponse.json(rawJoinToken) ), ], }, }; const Provider = props => { - const ctx = createTeleportContext(); - const discoverCtx: DiscoverContextState = { - agentMeta: { - resourceName: 'db-name', - agentMatcherLabels: [], - db: {} as any, - selectedAwsRdsDb: {} as any, - ...props.agentMeta, - }, - currentStep: 0, - nextStep: () => null, - prevStep: () => null, - onSelectResource: () => null, - resourceSpec: { - dbMeta: { - location: DatabaseLocation.Aws, - engine: DatabaseEngine.AuroraMysql, - }, - } as any, - exitFlow: () => null, - viewConfig: null, - indexedViews: [], - setResourceSpec: () => null, - updateAgentMeta: () => null, - emitErrorEvent: () => null, - emitEvent: () => null, - eventState: null, - }; - return ( - - - - - - {props.children} - - - - - + {props.children} + ); }; -function createTeleportContext() { - const ctx = new TeleportContext(); - - ctx.isEnterprise = false; - ctx.storeUser.setState(getUserContext()); - - return ctx; -} - const rawJoinToken = { id: 'some-id', roles: ['Node'], diff --git a/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.story.tsx b/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.story.tsx index d883a3345783d..5b4a095235db7 100644 --- a/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.story.tsx +++ b/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.story.tsx @@ -18,22 +18,13 @@ import { delay, http, HttpResponse } from 'msw'; import { useEffect } from 'react'; -import { MemoryRouter } from 'react-router'; import { withoutQuery } from 'web/packages/build/storybook'; import { Info } from 'design/Alert'; -import { ContextProvider } from 'teleport'; import cfg from 'teleport/config'; -import { - DatabaseEngine, - DatabaseLocation, -} from 'teleport/Discover/SelectResource'; -import { - DiscoverContextState, - DiscoverProvider, -} from 'teleport/Discover/useDiscover'; -import { createTeleportContext } from 'teleport/mocks/contexts'; +import { resourceSpecAwsRdsPostgres } from 'teleport/Discover/Fixtures/databases'; +import { RequiredDiscoverProviders } from 'teleport/Discover/Fixtures/fixtures'; import { IntegrationKind, IntegrationStatusCode, @@ -271,60 +262,31 @@ WithOneOfDbListError.parameters = { }; const Component = () => { - const ctx = createTeleportContext(); - const discoverCtx: DiscoverContextState = { - agentMeta: { - resourceName: 'db-name', - agentMatcherLabels: [], - db: {} as any, - selectedAwsRdsDb: {} as any, - node: {} as any, - awsIntegration: { - kind: IntegrationKind.AwsOidc, - name: 'test-oidc', - resourceType: 'integration', - spec: { - roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', - issuerS3Bucket: '', - issuerS3Prefix: '', - }, - statusCode: IntegrationStatusCode.Running, - }, - }, - currentStep: 0, - nextStep: () => null, - prevStep: () => null, - onSelectResource: () => null, - resourceSpec: { - dbMeta: { - location: DatabaseLocation.Aws, - engine: DatabaseEngine.Postgres, - }, - } as any, - exitFlow: () => null, - viewConfig: null, - indexedViews: [], - setResourceSpec: () => null, - updateAgentMeta: () => null, - emitErrorEvent: () => null, - emitEvent: () => null, - eventState: null, - }; - - cfg.proxyCluster = 'localhost'; return ( - - - - Devs: Select any region to see story state - - - - + Devs: Select any region to see story state + + ); }; diff --git a/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.test.tsx b/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.test.tsx index 53e84624adcde..1ec4eda4e8abd 100644 --- a/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.test.tsx +++ b/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.test.tsx @@ -19,7 +19,11 @@ import { act, fireEvent, render, screen } from 'design/utils/testing'; import cfg from 'teleport/config'; -import { ComponentWrapper } from 'teleport/Discover/Fixtures/databases'; +import { + getSelectedAwsPostgresDbMeta, + resourceSpecAwsRdsPostgres, +} from 'teleport/Discover/Fixtures/databases'; +import { RequiredDiscoverProviders } from 'teleport/Discover/Fixtures/fixtures'; import DatabaseService from 'teleport/services/databases/databases'; import * as discoveryService from 'teleport/services/discovery/discovery'; import { DISCOVERY_GROUP_CLOUD } from 'teleport/services/discovery/discovery'; @@ -222,7 +226,10 @@ const mockAwsDbs: AwsRdsDatabase[] = [ ]; const Component = () => ( - + - + ); diff --git a/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.tsx b/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.tsx index 8080cd263b975..c0576558a74e3 100644 --- a/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.tsx +++ b/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.tsx @@ -140,7 +140,7 @@ export function EnrollRdsDatabase() { }; return ( - + <>
Enroll RDS Database
{fetchAttempt.status === 'failed' && !hasIamPermError && ( {fetchAttempt.statusText} @@ -200,6 +200,6 @@ export function EnrollRdsDatabase() { key={mainContentProps.vpc?.id} /> )} -
+ ); } diff --git a/web/packages/teleport/src/Discover/Database/IamPolicy/IamPolicy.story.tsx b/web/packages/teleport/src/Discover/Database/IamPolicy/IamPolicy.story.tsx index 83ad566a48955..5d56a399f33d5 100644 --- a/web/packages/teleport/src/Discover/Database/IamPolicy/IamPolicy.story.tsx +++ b/web/packages/teleport/src/Discover/Database/IamPolicy/IamPolicy.story.tsx @@ -18,6 +18,8 @@ import { MemoryRouter } from 'react-router'; +import { DiscoverBox } from 'teleport/Discover/Shared'; + import { IamPolicyView } from './IamPolicy'; import type { State } from './useIamPolicy'; @@ -27,22 +29,28 @@ export default { export const Loaded = () => ( - + + + ); export const Failed = () => ( - + + + ); export const Processing = () => ( - + + + ); diff --git a/web/packages/teleport/src/Discover/Database/IamPolicy/IamPolicy.tsx b/web/packages/teleport/src/Discover/Database/IamPolicy/IamPolicy.tsx index 939ce2b4fdae4..33a719717d2d9 100644 --- a/web/packages/teleport/src/Discover/Database/IamPolicy/IamPolicy.tsx +++ b/web/packages/teleport/src/Discover/Database/IamPolicy/IamPolicy.tsx @@ -47,7 +47,7 @@ export function IamPolicyView({ iamPolicyName, }: State) { return ( - + <>
Configure IAM Policy
Teleport needs AWS IAM permissions to be able to discover and register @@ -120,6 +120,6 @@ export function IamPolicyView({ /> nextStep(0)} /> -
+ ); } diff --git a/web/packages/teleport/src/Discover/Database/MutualTls/MutualTls.story.tsx b/web/packages/teleport/src/Discover/Database/MutualTls/MutualTls.story.tsx index 8c419c3a88841..2763c81b3226d 100644 --- a/web/packages/teleport/src/Discover/Database/MutualTls/MutualTls.story.tsx +++ b/web/packages/teleport/src/Discover/Database/MutualTls/MutualTls.story.tsx @@ -18,6 +18,8 @@ import { MemoryRouter } from 'react-router'; +import { DiscoverBox } from 'teleport/Discover/Shared'; + import { DatabaseEngine } from '../../SelectResource'; import { MutualTlsView } from './MutualTls'; import type { State } from './useMutualTls'; @@ -28,40 +30,52 @@ export default { export const LoadedPostgres = () => ( - + + + ); export const LoadedMongo = () => ( - + + + ); export const LoadedSqlMaria = () => ( - + + + ); export const NoPerm = () => ( - + + + ); export const Failed = () => ( - + + + ); export const Processing = () => ( - + + + ); diff --git a/web/packages/teleport/src/Discover/Database/MutualTls/MutualTls.tsx b/web/packages/teleport/src/Discover/Database/MutualTls/MutualTls.tsx index f027a2a82957c..e0fa97cce7ed3 100644 --- a/web/packages/teleport/src/Discover/Database/MutualTls/MutualTls.tsx +++ b/web/packages/teleport/src/Discover/Database/MutualTls/MutualTls.tsx @@ -52,7 +52,7 @@ export function MutualTlsView({ const [caCert, setCaCert] = useState(''); return ( - + <>
Configure Mutual TLS
Self-hosted databases must be configured with Teleport's certificate @@ -112,7 +112,6 @@ export function MutualTlsView({ autoFocus textAreaCss={` height: 100px; - width: 800px; `} />
@@ -123,7 +122,7 @@ export function MutualTlsView({ onProceed={() => onNextStep(caCert)} disableProceed={attempt.status === 'processing'} /> - + ); } diff --git a/web/packages/teleport/src/Discover/Database/SetupAccess/SetupAccess.story.tsx b/web/packages/teleport/src/Discover/Database/SetupAccess/SetupAccess.story.tsx index 8cbd325430619..6488e09531d24 100644 --- a/web/packages/teleport/src/Discover/Database/SetupAccess/SetupAccess.story.tsx +++ b/web/packages/teleport/src/Discover/Database/SetupAccess/SetupAccess.story.tsx @@ -20,14 +20,15 @@ import { http, HttpResponse } from 'msw'; import cfg from 'teleport/config'; import { - getDbMeta, - getDbResourceSpec, + getSelectedAwsPostgresDbMeta, + resourceSpecAwsRdsMySql, + resourceSpecAwsRdsPostgres, + resourceSpecSelfHostedMysql, + resourceSpecSelfHostedPostgres, } from 'teleport/Discover/Fixtures/databases'; -import { TeleportProvider } from 'teleport/Discover/Fixtures/fixtures'; -import { ResourceKind } from 'teleport/Discover/Shared'; +import { RequiredDiscoverProviders } from 'teleport/Discover/Fixtures/fixtures'; import { getAcl, noAccess } from 'teleport/mocks/contexts'; -import { DatabaseEngine, DatabaseLocation } from '../../SelectResource'; import SetupAccess from './SetupAccess'; export default { @@ -48,20 +49,16 @@ export default { }; export const NoTraits = () => { - const meta = getDbMeta(); + const meta = getSelectedAwsPostgresDbMeta(); meta.db.users = []; meta.db.names = []; return ( - - + ); }; NoTraits.parameters = { @@ -75,28 +72,20 @@ NoTraits.parameters = { }; export const WithTraitsAwsPostgres = () => ( - - + ); export const WithTraitsAwsPostgresAutoEnroll = () => { - const meta = getDbMeta(); + const meta = getSelectedAwsPostgresDbMeta(); meta.db = undefined; return ( - { } > - + ); }; export const WithTraitsAwsMySql = () => ( - - + ); export const WithTraitsPostgres = () => ( - - -); - -export const WithTraitsMongo = () => ( - - - + ); export const WithTraitsMySql = () => ( - - + ); export const NoAccess = () => ( - - + ); export const SsoUser = () => ( - - + ); const dynamicTraits = { diff --git a/web/packages/teleport/src/Discover/Database/SetupAccess/SetupAccess.tsx b/web/packages/teleport/src/Discover/Database/SetupAccess/SetupAccess.tsx index ff65ffac1dfe0..84191e84d7e0e 100644 --- a/web/packages/teleport/src/Discover/Database/SetupAccess/SetupAccess.tsx +++ b/web/packages/teleport/src/Discover/Database/SetupAccess/SetupAccess.tsx @@ -333,34 +333,6 @@ function DbEngineInstructions({ ); } - if (dbEngine === DatabaseEngine.MongoDb) { - return ( - - - To create a user for this database, connect to this database using - the mongosh - or mongo shell and run the following command: - - - - ); - } - if (dbEngine === DatabaseEngine.MySql) { return ( diff --git a/web/packages/teleport/src/Discover/Database/TestConnection/TestConnection.story.tsx b/web/packages/teleport/src/Discover/Database/TestConnection/TestConnection.story.tsx index 4cd1ec4927fa8..b1042cf3665f6 100644 --- a/web/packages/teleport/src/Discover/Database/TestConnection/TestConnection.story.tsx +++ b/web/packages/teleport/src/Discover/Database/TestConnection/TestConnection.story.tsx @@ -16,108 +16,70 @@ * along with this program. If not, see . */ -import React, { PropsWithChildren } from 'react'; -import { MemoryRouter } from 'react-router'; +import { Info } from 'design/Alert'; -import { ContextProvider } from 'teleport'; -import cfg from 'teleport/config'; import { - DiscoverContextState, - DiscoverProvider, -} from 'teleport/Discover/useDiscover'; -import { createTeleportContext } from 'teleport/mocks/contexts'; + resourceSpecAwsRdsMySql, + resourceSpecAwsRdsPostgres, +} from 'teleport/Discover/Fixtures/databases'; +import { RequiredDiscoverProviders } from 'teleport/Discover/Fixtures/fixtures'; +import { AgentMeta } from 'teleport/Discover/useDiscover'; import { IntegrationKind, IntegrationStatusCode, } from 'teleport/services/integrations'; -import { DatabaseEngine, DatabaseLocation } from '../../SelectResource'; import { TestConnection } from './TestConnection'; export default { title: 'Teleport/Discover/Database/TestConnection', }; +const agentMeta: AgentMeta = { + resourceName: 'db-name', + agentMatcherLabels: [], + db: { + kind: 'db', + name: 'postgres', + description: 'PostgreSQL 11.6: AWS postgres ', + type: 'RDS PostgreSQL', + protocol: 'postgres', + labels: [ + { name: 'cluster', value: 'root' }, + { name: 'env', value: 'aws' }, + ], + hostname: 'postgres-hostname', + names: ['name1', 'name2', '*'], + users: ['user1', 'user2', '*'], + }, + awsIntegration: { + kind: IntegrationKind.AwsOidc, + name: 'test-oidc', + resourceType: 'integration', + spec: { + roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', + issuerS3Bucket: '', + issuerS3Prefix: '', + }, + statusCode: IntegrationStatusCode.Running, + }, +}; + export const InitMySql = () => ( - - - - - + + Devs: mysql allows database names to be empty + + ); export const InitPostgres = () => ( - - - - - + + + ); - -const Provider: React.FC> = ({ - children, - dbEngine, -}) => { - const ctx = createTeleportContext(); - const discoverCtx: DiscoverContextState = { - agentMeta: { - resourceName: 'db-name', - agentMatcherLabels: [], - db: { - kind: 'db', - name: 'aurora', - description: 'PostgreSQL 11.6: AWS Aurora ', - type: 'RDS PostgreSQL', - protocol: 'postgres', - labels: [ - { name: 'cluster', value: 'root' }, - { name: 'env', value: 'aws' }, - ], - hostname: 'aurora-hostname', - names: ['name1', 'name2', '*'], - users: ['user1', 'user2', '*'], - }, - awsIntegration: { - kind: IntegrationKind.AwsOidc, - name: 'test-oidc', - resourceType: 'integration', - spec: { - roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', - issuerS3Bucket: '', - issuerS3Prefix: '', - }, - statusCode: IntegrationStatusCode.Running, - }, - }, - currentStep: 0, - onSelectResource: () => null, - resourceSpec: { - dbMeta: { - location: DatabaseLocation.Aws, - engine: dbEngine, - }, - } as any, - exitFlow: () => null, - viewConfig: null, - indexedViews: [], - setResourceSpec: () => null, - updateAgentMeta: () => null, - emitErrorEvent: () => null, - emitEvent: () => null, - eventState: null, - nextStep: () => null, - prevStep: () => null, - }; - - return ( - - - {children} - - - ); -}; diff --git a/web/packages/teleport/src/Discover/Database/TestConnection/TestConnection.test.tsx b/web/packages/teleport/src/Discover/Database/TestConnection/TestConnection.test.tsx index b33869372152d..a5aea941f828e 100644 --- a/web/packages/teleport/src/Discover/Database/TestConnection/TestConnection.test.tsx +++ b/web/packages/teleport/src/Discover/Database/TestConnection/TestConnection.test.tsx @@ -19,14 +19,10 @@ import { render, screen, userEvent } from 'design/utils/testing'; import { - ComponentWrapper, - getDbMeta, - getDbResourceSpec, + getSelectedAwsPostgresDbMeta, + resourceSpecSelfHostedMysql, } from 'teleport/Discover/Fixtures/databases'; -import { - DatabaseEngine, - DatabaseLocation, -} from 'teleport/Discover/SelectResource'; +import { RequiredDiscoverProviders } from 'teleport/Discover/Fixtures/fixtures'; import { agentService } from 'teleport/services/agents'; import auth from 'teleport/services/auth/auth'; import { userEventService } from 'teleport/services/userEvent'; @@ -50,20 +46,17 @@ afterEach(() => { }); test('custom db name and user is respected when defined', async () => { - const dbMeta = getDbMeta(); + const dbMeta = getSelectedAwsPostgresDbMeta(); dbMeta.db.users = ['user1', '*']; dbMeta.db.names = ['name1', '*']; render( - - + ); // Test with default user and names. diff --git a/web/packages/teleport/src/Discover/Discover.test.tsx b/web/packages/teleport/src/Discover/Discover.test.tsx index 289dbaf9172e0..a3f949613dafb 100644 --- a/web/packages/teleport/src/Discover/Discover.test.tsx +++ b/web/packages/teleport/src/Discover/Discover.test.tsx @@ -32,15 +32,19 @@ import { KUBERNETES, SERVERS, } from 'teleport/Discover/SelectResource/resources'; -import type { ResourceSpec } from 'teleport/Discover/SelectResource/types'; import { getOSSFeatures } from 'teleport/features'; import { FeaturesContextProvider } from 'teleport/FeaturesContext'; +import { InfoGuidePanelProvider } from 'teleport/Main/InfoGuideContext'; import { createTeleportContext, getAcl } from 'teleport/mocks/contexts'; import { makeDefaultUserPreferences } from 'teleport/services/userPreferences/userPreferences'; import TeleportContextProvider from 'teleport/TeleportContextProvider'; import { makeTestUserContext } from 'teleport/User/testHelpers/makeTestUserContext'; import { mockUserContextProviderWith } from 'teleport/User/testHelpers/mockUserContextWith'; +import { + resourceSpecConnectMyComputer, + resourceSpecSamlGcp, +} from './Fixtures/fixtures'; import { ResourceKind } from './Shared'; import { getGuideTileId } from './testUtils'; import { DiscoverUpdateProps, useDiscover } from './useDiscover'; @@ -77,7 +81,9 @@ const create = ({ initialEntry = '', preferredResource }: createProps) => { > - + + + @@ -285,23 +291,19 @@ const renderUpdate = (props: DiscoverUpdateProps) => { ]} > - + + + ); }; 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: '' } }); + renderUpdate({ + resourceSpec: resourceSpecConnectMyComputer, + agentMeta: { resourceName: '' }, + }); expect(screen.queryByTestId(ResourceKind.Server)).not.toBeInTheDocument(); @@ -317,17 +319,8 @@ test('update flow: renders single component based on resourceSpec', () => { }); 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, + resourceSpec: resourceSpecSamlGcp, agentMeta: { resourceName: 'saml2' }, }); diff --git a/web/packages/teleport/src/Discover/Discover.tsx b/web/packages/teleport/src/Discover/Discover.tsx index 8b723b32af020..ccb37d48ea34a 100644 --- a/web/packages/teleport/src/Discover/Discover.tsx +++ b/web/packages/teleport/src/Discover/Discover.tsx @@ -20,16 +20,19 @@ import React from 'react'; import { useLocation } from 'react-router'; import { Prompt } from 'react-router-dom'; -import { Box } from 'design'; +import { Box, Flex } from 'design'; import { FeatureBox } from 'teleport/components/Layout'; +import { InfoGuideWrapper } from 'teleport/components/SlidingSidePanel/InfoGuideSidePanel'; import { findViewAtIndex } from 'teleport/components/Wizard/flow'; import { Navigation } from 'teleport/components/Wizard/Navigation'; import cfg from 'teleport/config'; import type { View } from 'teleport/Discover/flow'; import { SelectResource } from 'teleport/Discover/SelectResource/SelectResource'; +import { DiscoverBox } from 'teleport/Discover/Shared'; import { DiscoverEvent } from 'teleport/services/userEvent'; +import { getOverview } from './Overview/Overview'; import { DiscoverIcon } from './SelectResource/icons'; import { EViewConfigs } from './types'; import { @@ -57,7 +60,26 @@ function DiscoverContent() { const Component = currentView.component; - content = ; + const overview = getOverview({ resourceSpec: agentProps.resourceSpec }); + + if (!overview) { + content = ( + + + + ); + } else { + content = ( + + + + + + + + + ); + } if (viewConfig.wrapper) { content = viewConfig.wrapper(content); @@ -74,7 +96,7 @@ function DiscoverContent() { <> {hasSelectedResource && ( - + . */ -import React, { PropsWithChildren } from 'react'; - -import { - DatabaseEngine, - DatabaseLocation, - ResourceSpec, -} from 'teleport/Discover/SelectResource'; import { DbMeta } from 'teleport/Discover/useDiscover'; import { IamPolicyStatus } from 'teleport/services/databases'; import { IntegrationKind, IntegrationStatusCode, } from 'teleport/services/integrations'; +import { DiscoverGuideId } from 'teleport/services/userPreferences/discoverPreference'; import { DATABASES } from '../SelectResource/resources'; -import { ResourceKind } from '../Shared'; -import { TeleportProvider } from './fixtures'; -export function getDbResourceSpec( - engine: DatabaseEngine, - location?: DatabaseLocation -): ResourceSpec { - return { - ...DATABASES[0], - dbMeta: { - engine, - location, - }, - }; -} +export const resourceSpecAwsRdsPostgres = DATABASES.find( + d => d.id === DiscoverGuideId.DatabaseAwsRdsPostgres +); + +export const resourceSpecAwsRdsAuroraMysql = DATABASES.find( + d => d.id === DiscoverGuideId.DatabaseAwsRdsAuroraMysql +); -export function getDbMeta(): DbMeta { +export const resourceSpecAwsRdsMySql = DATABASES.find( + d => d.id === DiscoverGuideId.DatabaseAwsRdsMysqlMariaDb +); + +export const resourceSpecSelfHostedPostgres = DATABASES.find( + d => d.id === DiscoverGuideId.DatabasePostgres +); + +export const resourceSpecSelfHostedMysql = DATABASES.find( + d => d.id === DiscoverGuideId.DatabaseMysql +); + +export function getSelectedAwsPostgresDbMeta(): DbMeta { return { resourceName: 'db-name', awsRegion: 'us-east-1', @@ -99,18 +98,3 @@ export function getDbMeta(): DbMeta { }, }; } - -export const ComponentWrapper: React.FC< - PropsWithChildren<{ resourceSpec?: ResourceSpec; dbMeta?: DbMeta }> -> = ({ children, resourceSpec, dbMeta }) => ( - - {children} - -); diff --git a/web/packages/teleport/src/Discover/Fixtures/fixtures.tsx b/web/packages/teleport/src/Discover/Fixtures/fixtures.tsx index 63f33ce713d9f..df21111722ac2 100644 --- a/web/packages/teleport/src/Discover/Fixtures/fixtures.tsx +++ b/web/packages/teleport/src/Discover/Fixtures/fixtures.tsx @@ -16,13 +16,13 @@ * along with this program. If not, see . */ +import { LocationDescriptor } from 'history'; import React, { PropsWithChildren } from 'react'; import { MemoryRouter } from 'react-router'; import { ContextProvider } from 'teleport'; import cfg from 'teleport/config'; -import { ResourceSpec } from 'teleport/Discover/SelectResource'; -import { ResourceKind } from 'teleport/Discover/Shared'; +import { DiscoverBox, ResourceKind } from 'teleport/Discover/Shared'; import { PingTeleportProvider } from 'teleport/Discover/Shared/PingTeleportContext'; import { AgentMeta, @@ -30,52 +30,85 @@ import { DiscoverProvider, } from 'teleport/Discover/useDiscover'; import { FeaturesContextProvider } from 'teleport/FeaturesContext'; +import { InfoGuidePanelProvider } from 'teleport/Main/InfoGuideContext'; import { createTeleportContext } from 'teleport/mocks/contexts'; import { Acl, AuthType } from 'teleport/services/user'; +import { DiscoverGuideId } from 'teleport/services/userPreferences/discoverPreference'; +import TeleportContext from 'teleport/teleportContext'; +import { ThemeProvider } from 'teleport/ThemeProvider'; +import { TeleportFeature } from 'teleport/types'; -export const TeleportProvider: React.FC< +import { + APPLICATIONS, + KUBERNETES, + SAML_APPLICATIONS, + SelectResourceSpec, + SERVERS, +} from '../SelectResource/resources'; + +export const RequiredDiscoverProviders: React.FC< PropsWithChildren<{ agentMeta: AgentMeta; - resourceSpec?: ResourceSpec; + resourceSpec: SelectResourceSpec; interval?: number; customAcl?: Acl; authType?: AuthType; - resourceKind: ResourceKind; + teleportCtx?: TeleportContext; + discoverCtx?: DiscoverContextState; + features?: TeleportFeature[]; + initialEntries?: LocationDescriptor[]; }> > = props => { - const ctx = createTeleportContext({ customAcl: props.customAcl }); + let ctx = createTeleportContext({ customAcl: props.customAcl }); + if (props.teleportCtx) { + ctx = props.teleportCtx; + } if (props.authType) { ctx.storeUser.state.authType = props.authType; } - const discoverCtx = defaultDiscoverContext({ - agentMeta: props.agentMeta, - resourceSpec: props.resourceSpec, - }); + let discoverCtx; + if (props.agentMeta && props.resourceSpec) { + discoverCtx = emptyDiscoverContext({ + agentMeta: props.agentMeta, + resourceSpec: props.resourceSpec, + }); + } + if (props.discoverCtx) { + discoverCtx = props.discoverCtx; + } return ( - - - - - - {props.children} - - - - + + + + + + + + {props.children} + + + + + + ); }; -export function defaultDiscoverContext({ +export function emptyDiscoverContext({ agentMeta, resourceSpec, }: { agentMeta?: AgentMeta; - resourceSpec?: ResourceSpec; + resourceSpec?: SelectResourceSpec; }): DiscoverContextState { return { agentMeta: agentMeta @@ -93,16 +126,45 @@ export function defaultDiscoverContext({ nextStep: () => null, prevStep: () => null, onSelectResource: () => null, - resourceSpec: resourceSpec ? resourceSpec : defaultResourceSpec(null), + resourceSpec: resourceSpec ? resourceSpec : emptyResourceSpec(null), }; } -export function defaultResourceSpec(kind: ResourceKind): ResourceSpec { +export function emptyResourceSpec(kind: ResourceKind): SelectResourceSpec { return { name: '', kind, icon: null, keywords: [], event: null, + id: null, }; } + +export const resourceSpecAwsEks = KUBERNETES.find( + k => k.id === DiscoverGuideId.KubernetesAwsEks +); + +export const resourceSpecSelfHostedKube = KUBERNETES.find( + k => k.id === DiscoverGuideId.Kubernetes +); + +export const resourceSpecAwsEc2Ssm = SERVERS.find( + s => s.id === DiscoverGuideId.ServerAwsEc2Ssm +); + +export const resourceSpecServerLinuxUbuntu = SERVERS.find( + s => s.id === DiscoverGuideId.ServerLinuxUbuntu +); + +export const resourceSpecConnectMyComputer = SERVERS.find( + s => s.id === DiscoverGuideId.ConnectMyComputer +); + +export const resourceSpecAppAwsCliConsole = APPLICATIONS.find( + a => a.id === DiscoverGuideId.ApplicationAwsCliConsole +); + +export const resourceSpecSamlGcp = SAML_APPLICATIONS.find( + s => s.id === DiscoverGuideId.ApplicationSamlWorkforceIdentityFederation +); diff --git a/web/packages/teleport/src/Discover/Fixtures/kubernetes.tsx b/web/packages/teleport/src/Discover/Fixtures/kubernetes.tsx deleted file mode 100644 index 3c57e36be34e8..0000000000000 --- a/web/packages/teleport/src/Discover/Fixtures/kubernetes.tsx +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Teleport - * Copyright (C) 2024 Gravitational, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import React, { PropsWithChildren } from 'react'; - -import { TeleportProvider } from 'teleport/Discover/Fixtures/fixtures'; -import { KubeLocation, ResourceSpec } from 'teleport/Discover/SelectResource'; -import { KUBERNETES } from 'teleport/Discover/SelectResource/resources'; -import { ResourceKind } from 'teleport/Discover/Shared'; -import { EksMeta } from 'teleport/Discover/useDiscover'; -import { - IntegrationKind, - IntegrationStatusCode, -} from 'teleport/services/integrations'; - -export function getKubeResourceSpec(location?: KubeLocation): ResourceSpec { - return { - ...KUBERNETES[1], - kubeMeta: { - location, - }, - }; -} - -export function getEksMeta(): EksMeta { - return { - resourceName: 'eks1', - awsRegion: 'us-east-1', - agentMatcherLabels: [], - kube: { - kind: 'kube_cluster', - name: 'eks1', - labels: [], - }, - awsIntegration: { - kind: IntegrationKind.AwsOidc, - name: 'test-integration', - resourceType: 'integration', - spec: { - roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', - issuerS3Bucket: '', - issuerS3Prefix: '', - }, - statusCode: IntegrationStatusCode.Running, - }, - }; -} - -export const ComponentWrapper: React.FC = ({ children }) => ( - - {children} - -); diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/Dialogs.story.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/Dialogs.story.tsx index 21331e339145e..d662e726e33a5 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/Dialogs.story.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/Dialogs.story.tsx @@ -22,14 +22,15 @@ import { MemoryRouter } from 'react-router'; import { ContextProvider } from 'teleport'; import cfg from 'teleport/config'; +import { + RequiredDiscoverProviders, + resourceSpecAwsEks, +} from 'teleport/Discover/Fixtures/fixtures'; import { generateCmd } from 'teleport/Discover/Kubernetes/SelfHosted'; import { ResourceKind } from 'teleport/Discover/Shared'; import { PingTeleportProvider } from 'teleport/Discover/Shared/PingTeleportContext'; import { clearCachedJoinTokenResult } from 'teleport/Discover/Shared/useJoinTokenSuspender'; -import { - DiscoverContextState, - DiscoverProvider, -} from 'teleport/Discover/useDiscover'; +import { AgentMeta } from 'teleport/Discover/useDiscover'; import { createTeleportContext } from 'teleport/mocks/contexts'; import { IntegrationKind, @@ -39,7 +40,6 @@ import { INTERNAL_RESOURCE_ID_LABEL_KEY, JoinToken, } from 'teleport/services/joinToken'; -import { DiscoverEventResource } from 'teleport/services/userEvent'; import { AgentWaitingDialog } from './AgentWaitingDialog'; import { EnrollmentDialog } from './EnrollmentDialog'; @@ -139,49 +139,29 @@ const helmCommandProps = { ], }; -export const ManualHelmDialogStory = () => { - const discoverCtx: DiscoverContextState = { - agentMeta: { - resourceName: 'kube-name', - agentMatcherLabels: [], - kube: { - kind: 'kube_cluster', - name: '', - labels: [], - }, - awsIntegration: { - kind: IntegrationKind.AwsOidc, - name: 'test-oidc', - resourceType: 'integration', - spec: { - roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', - issuerS3Bucket: '', - issuerS3Prefix: '', - }, - statusCode: IntegrationStatusCode.Running, - }, - }, - currentStep: 0, - nextStep: () => null, - prevStep: () => null, - onSelectResource: () => null, - resourceSpec: { - name: 'Eks', - kind: ResourceKind.Kubernetes, - icon: 'eks', - keywords: [], - event: DiscoverEventResource.KubernetesEks, +const agentMeta: AgentMeta = { + resourceName: 'kube-name', + agentMatcherLabels: [], + kube: { + kind: 'kube_cluster', + name: '', + labels: [], + }, + awsIntegration: { + kind: IntegrationKind.AwsOidc, + name: 'test-oidc', + resourceType: 'integration', + spec: { + roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', + issuerS3Bucket: '', + issuerS3Prefix: '', }, - exitFlow: () => null, - viewConfig: null, - indexedViews: [], - setResourceSpec: () => null, - updateAgentMeta: () => null, - emitErrorEvent: () => null, - emitEvent: () => null, - eventState: null, - }; + statusCode: IntegrationStatusCode.Running, + }, +}; +export const ManualHelmDialogStory = () => { + const [, setToken] = useState(); useEffect(() => { return () => { clearCachedJoinTokenResult([ @@ -192,29 +172,22 @@ export const ManualHelmDialogStory = () => { }; }, []); - const [, setToken] = useState(); - return ( - - - - { - // Emulate real usage of ManualHelmDialog where setJoinTokenAndGetCommand updates the - // state of a parent. - setToken(token); - return generateCmd(helmCommandProps); - }} - confirmedCommands={() => {}} - cancel={() => {}} - /> - - - + { + // Emulate real usage of ManualHelmDialog where setJoinTokenAndGetCommand updates the + // state of a parent. + setToken(token); + return generateCmd(helmCommandProps); + }} + confirmedCommands={() => {}} + cancel={() => {}} + /> + ); }; ManualHelmDialogStory.storyName = 'ManualHelmDialog'; diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEKSCluster.test.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEKSCluster.test.tsx index 2ed8bc057e9d7..5bf847a55c303 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEKSCluster.test.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEKSCluster.test.tsx @@ -19,7 +19,11 @@ import { act, fireEvent, render, screen } from 'design/utils/testing'; import cfg from 'teleport/config'; -import { ComponentWrapper } from 'teleport/Discover/Fixtures/kubernetes'; +import { + RequiredDiscoverProviders, + resourceSpecAwsEks, +} from 'teleport/Discover/Fixtures/fixtures'; +import { AgentMeta } from 'teleport/Discover/useDiscover'; import auth from 'teleport/services/auth'; import * as discoveryService from 'teleport/services/discovery/discovery'; import { @@ -28,7 +32,9 @@ import { } from 'teleport/services/discovery/discovery'; import { AwsEksCluster, + IntegrationKind, integrationService, + IntegrationStatusCode, } from 'teleport/services/integrations'; import KubeService from 'teleport/services/kube/kube'; import { userEventService } from 'teleport/services/userEvent'; @@ -262,8 +268,33 @@ const mockEKSClusters: AwsEksCluster[] = [ }, ]; +const agentMeta: AgentMeta = { + resourceName: 'eks1', + awsRegion: 'us-east-1', + agentMatcherLabels: [], + kube: { + kind: 'kube_cluster', + name: 'eks1', + labels: [], + }, + awsIntegration: { + kind: IntegrationKind.AwsOidc, + name: 'test-integration', + resourceType: 'integration', + spec: { + roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', + issuerS3Bucket: '', + issuerS3Prefix: '', + }, + statusCode: IntegrationStatusCode.Running, + }, +}; + const Component = () => ( - + - + ); diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.story.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.story.tsx index 77e4ff0d5f263..cb1e125cbce0a 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.story.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.story.tsx @@ -17,20 +17,18 @@ */ import { delay, http, HttpResponse } from 'msw'; import { useEffect } from 'react'; -import { MemoryRouter } from 'react-router'; import { Info } from 'design/Alert'; -import { ContextProvider } from 'teleport'; import cfg from 'teleport/config'; +import { + RequiredDiscoverProviders, + resourceSpecAwsEks, +} from 'teleport/Discover/Fixtures/fixtures'; import { ResourceKind } from 'teleport/Discover/Shared'; -import { PingTeleportProvider } from 'teleport/Discover/Shared/PingTeleportContext'; import { clearCachedJoinTokenResult } from 'teleport/Discover/Shared/useJoinTokenSuspender'; -import { - DiscoverContextState, - DiscoverProvider, -} from 'teleport/Discover/useDiscover'; -import { createTeleportContext, getUserContext } from 'teleport/mocks/contexts'; +import { AgentMeta } from 'teleport/Discover/useDiscover'; +import { getUserContext } from 'teleport/mocks/contexts'; import { AwsEksCluster, IntegrationKind, @@ -38,7 +36,6 @@ import { } from 'teleport/services/integrations'; import { INTERNAL_RESOURCE_ID_LABEL_KEY } from 'teleport/services/joinToken'; import { Kube } from 'teleport/services/kube'; -import { DiscoverEventResource } from 'teleport/services/userEvent/types'; import { EnrollEksCluster } from './EnrollEksCluster'; @@ -242,73 +239,36 @@ WithOtherError.parameters = { }, }; -const Component = ({ devInfoText = '' }) => { - const ctx = createTeleportContext(); - const discoverCtx: DiscoverContextState = { - agentMeta: { - resourceName: 'db-name', - agentMatcherLabels: [], - kube: { - kind: 'kube_cluster', - name: '', - labels: [], - }, - awsIntegration: { - kind: IntegrationKind.AwsOidc, - name: integrationName, - resourceType: 'integration', - spec: { - roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', - issuerS3Bucket: '', - issuerS3Prefix: '', - }, - statusCode: IntegrationStatusCode.Running, - }, - }, - currentStep: 0, - nextStep: () => null, - prevStep: () => null, - onSelectResource: () => null, - resourceSpec: { - name: 'Eks', - kind: ResourceKind.Kubernetes, - icon: 'eks', - keywords: [], - event: DiscoverEventResource.KubernetesEks, +const agentMeta: AgentMeta = { + resourceName: 'kube-name', + agentMatcherLabels: [], + kube: { + kind: 'kube_cluster', + name: '', + labels: [], + }, + awsIntegration: { + kind: IntegrationKind.AwsOidc, + name: integrationName, + resourceType: 'integration', + spec: { + roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', + issuerS3Bucket: '', + issuerS3Prefix: '', }, - exitFlow: () => null, - viewConfig: null, - indexedViews: [], - setResourceSpec: () => null, - updateAgentMeta: () => null, - emitErrorEvent: () => null, - emitEvent: () => null, - eventState: null, - }; + statusCode: IntegrationStatusCode.Running, + }, +}; +const Component = ({ devInfoText = '' }) => { return ( - - - - - - {devInfoText || 'Devs: Select any region to see story state'} - - - - - - + {devInfoText || 'Devs: Select any region to see story state'} + null} updateAgentMeta={() => null} /> + ); }; diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx index efdad9aacad5b..ae4ac9dccf635 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx @@ -17,7 +17,6 @@ */ import { useCallback, useState } from 'react'; -import styled from 'styled-components'; import { Box, @@ -70,7 +69,7 @@ import { import { useV1Fallback } from 'teleport/services/version/unsupported'; import useTeleport from 'teleport/useTeleport'; -import { ActionButtons, Header, LabelsCreater } from '../../Shared'; +import { ActionButtons, Header, LabelsCreater, StyledBox } from '../../Shared'; import { AgentWaitingDialog } from './AgentWaitingDialog'; import { ClustersList } from './EksClustersList'; import { EnrollmentDialog } from './EnrollmentDialog'; @@ -654,10 +653,3 @@ export function EnrollEksCluster(props: AgentStepProps) { ); } - -const StyledBox = styled(Box)` - max-width: 1000px; - background-color: ${props => props.theme.colors.spotBackground[0]}; - padding: ${props => `${props.theme.space[3]}px`}; - border-radius: ${props => `${props.theme.space[2]}px`}; -`; diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx index 21c7fbbe23c97..483e732ba992a 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/ManualHelmDialog.tsx @@ -17,7 +17,6 @@ */ import React, { Suspense, useEffect, useState } from 'react'; -import styled from 'styled-components'; import { Box, @@ -34,7 +33,7 @@ import { P } from 'design/Text/Text'; import { CatchError } from 'teleport/components/CatchError'; import { TextSelectCopyMulti } from 'teleport/components/TextSelectCopy'; -import { ResourceKind, TextIcon } from 'teleport/Discover/Shared'; +import { ResourceKind, StyledBox, TextIcon } from 'teleport/Discover/Shared'; import { CommandBox } from 'teleport/Discover/Shared/CommandBox'; import { clearCachedJoinTokenResult, @@ -175,10 +174,3 @@ export function ManualHelmDialog({ ); } - -const StyledBox = styled(Box)` - max-width: 1000px; - background-color: ${props => props.theme.colors.spotBackground[0]}; - padding: ${props => `${props.theme.space[3]}px`}; - border-radius: ${props => `${props.theme.space[2]}px`}; -`; diff --git a/web/packages/teleport/src/Discover/Kubernetes/SelfHosted/HelmChart/HelmChart.story.tsx b/web/packages/teleport/src/Discover/Kubernetes/SelfHosted/HelmChart/HelmChart.story.tsx index 911c013c81046..326b762e7b424 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/SelfHosted/HelmChart/HelmChart.story.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/SelfHosted/HelmChart/HelmChart.story.tsx @@ -18,25 +18,22 @@ import { StoryObj } from '@storybook/react'; import { delay, http, HttpResponse } from 'msw'; -import { MemoryRouter } from 'react-router'; +import { PropsWithChildren } from 'react'; import { withoutQuery } from 'web/packages/build/storybook'; -import { ContextProvider, Context as TeleportContext } from 'teleport'; import cfg from 'teleport/config'; +import { + RequiredDiscoverProviders, + resourceSpecSelfHostedKube, +} from 'teleport/Discover/Fixtures/fixtures'; import { ResourceKind } from 'teleport/Discover/Shared'; -import { PingTeleportProvider } from 'teleport/Discover/Shared/PingTeleportContext'; import { clearCachedJoinTokenResult } from 'teleport/Discover/Shared/useJoinTokenSuspender'; -import { - DiscoverContextState, - DiscoverProvider, -} from 'teleport/Discover/useDiscover'; -import { getUserContext } from 'teleport/mocks/contexts'; +import { AgentMeta } from 'teleport/Discover/useDiscover'; import { IntegrationKind, IntegrationStatusCode, } from 'teleport/services/integrations'; import { INTERNAL_RESOURCE_ID_LABEL_KEY } from 'teleport/services/joinToken'; -import { DiscoverEventResource } from 'teleport/services/userEvent'; import HelmChart from './HelmChart'; @@ -165,71 +162,32 @@ export const Failed: StoryObj = { }, }; -const Provider = props => { - const discoverCtx: DiscoverContextState = { - agentMeta: { - awsIntegration: { - kind: IntegrationKind.AwsOidc, - name: 'some-name', - resourceType: 'integration', - spec: { - roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', - issuerS3Bucket: '', - issuerS3Prefix: '', - }, - statusCode: IntegrationStatusCode.Running, - }, +const agentMeta: AgentMeta = { + awsIntegration: { + kind: IntegrationKind.AwsOidc, + name: 'some-name', + resourceType: 'integration', + spec: { + roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', + issuerS3Bucket: '', + issuerS3Prefix: '', }, - currentStep: 0, - nextStep: () => null, - prevStep: () => null, - onSelectResource: () => null, - resourceSpec: { - name: 'kube', - kind: ResourceKind.Kubernetes, - icon: 'kube', - keywords: [], - event: DiscoverEventResource.Kubernetes, - }, - exitFlow: () => null, - viewConfig: null, - indexedViews: [], - setResourceSpec: () => null, - updateAgentMeta: () => null, - emitErrorEvent: () => null, - emitEvent: () => null, - eventState: null, - }; + statusCode: IntegrationStatusCode.Running, + }, +}; +const Provider: React.FC> = props => { return ( - - - - - {props.children} - - - - + {props.children} + ); }; -function createTeleportContext() { - const ctx = new TeleportContext(); - - ctx.isEnterprise = false; - ctx.storeUser.setState(getUserContext()); - - return ctx; -} - const rawJoinToken = { id: 'some-id', roles: ['Node'], diff --git a/web/packages/teleport/src/Discover/Kubernetes/SelfHosted/HelmChart/HelmChart.tsx b/web/packages/teleport/src/Discover/Kubernetes/SelfHosted/HelmChart/HelmChart.tsx index c7454c23d5d98..3fa8756e3361a 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/SelfHosted/HelmChart/HelmChart.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/SelfHosted/HelmChart/HelmChart.tsx @@ -17,7 +17,6 @@ */ import { Suspense, useEffect, useState } from 'react'; -import styled from 'styled-components'; import { Alert, @@ -38,6 +37,7 @@ import { requiredField } from 'shared/components/Validation/rules'; import { CatchError } from 'teleport/components/CatchError'; import { TextSelectCopyMulti } from 'teleport/components/TextSelectCopy'; +import { StyledBox } from 'teleport/Discover/Shared'; import { CommandBox } from 'teleport/Discover/Shared/CommandBox'; import { usePingTeleport } from 'teleport/Discover/Shared/PingTeleportContext'; import { ResourceLabelTooltip } from 'teleport/Discover/Shared/ResourceLabelTooltip'; @@ -575,10 +575,3 @@ const InstallHelmChart = ({ ); }; - -const StyledBox = styled(Box)` - max-width: 1000px; - background-color: ${props => props.theme.colors.spotBackground[0]}; - padding: ${props => `${props.theme.space[3]}px`}; - border-radius: ${props => `${props.theme.space[2]}px`}; -`; diff --git a/web/packages/teleport/src/Discover/Kubernetes/SetupAccess/SetupAccess.story.tsx b/web/packages/teleport/src/Discover/Kubernetes/SetupAccess/SetupAccess.story.tsx index 53cc423a5f88e..87f5e0195709e 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/SetupAccess/SetupAccess.story.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/SetupAccess/SetupAccess.story.tsx @@ -18,6 +18,7 @@ import { MemoryRouter } from 'react-router'; +import { DiscoverBox } from 'teleport/Discover/Shared'; import { initSelectedOptionsHelper, type State, @@ -31,51 +32,61 @@ export default { export const NoTraits = () => ( - []} /> + + []} /> + ); export const WithTraits = () => ( - + + + ); export const WithTraitsAutoDiscovery = () => ( - + + }} + /> + ); export const NoAccess = () => ( - + + + ); export const SsoUser = () => ( - + + + ); diff --git a/web/packages/teleport/src/Discover/Kubernetes/TestConnection/TestConnection.story.tsx b/web/packages/teleport/src/Discover/Kubernetes/TestConnection/TestConnection.story.tsx index 7a11fc87e5d6f..08f09cbeb297c 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/TestConnection/TestConnection.story.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/TestConnection/TestConnection.story.tsx @@ -18,6 +18,8 @@ import { MemoryRouter } from 'react-router'; +import { DiscoverBox } from 'teleport/Discover/Shared'; + import { TestConnection } from './TestConnection'; import type { State } from './useTestConnection'; @@ -27,58 +29,68 @@ export default { export const InitWithLocal = () => ( - + + + ); export const InitWithSso = () => ( - + + + ); export const WithKubeUsers = () => ( - + + + ); export const WithKubeGroups = () => ( - + + + ); export const WithKubeUsersAndGroups = () => ( - + + + ); diff --git a/web/packages/teleport/src/Discover/Overview/Overview.tsx b/web/packages/teleport/src/Discover/Overview/Overview.tsx new file mode 100644 index 0000000000000..fccf17e5a2dd7 --- /dev/null +++ b/web/packages/teleport/src/Discover/Overview/Overview.tsx @@ -0,0 +1,306 @@ +/** + * Teleport + * Copyright (C) 2025 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { Link as InternalLink } from 'react-router-dom'; + +import { Mark } from 'design'; + +import { + InfoExternalTextLink, + InfoParagraph, + InfoTitle, + InfoUl, + ReferenceLink, + ReferenceLinks, +} from 'teleport/components/SlidingSidePanel/InfoGuideSidePanel'; +import cfg from 'teleport/config'; +import { DiscoverGuideId } from 'teleport/services/userPreferences/discoverPreference'; + +import { SelectResourceSpec } from '../SelectResource/resources'; + +const requiredAwsAccount = + 'AWS account with permissions to create and attach IAM policies.'; + +/** + * Returns info guide content to be rendered inside the InfoGuideSidePanel + * component. + * + * Content will depend on the "resourceSpec" id. + */ +export function getOverview({ + resourceSpec, +}: { + resourceSpec: SelectResourceSpec; +}): JSX.Element | null { + if (!resourceSpec.id) { + return null; + } + + let overview: JSX.Element; + let prereqs: JSX.Element; + let links: Record; + + switch (resourceSpec.id) { + case DiscoverGuideId.Kubernetes: + overview = ( + + This guide uses Helm to install the Teleport agent into a cluster, and + by default turns on auto-discovery of all apps in the cluster. + + ); + prereqs = ( + +
  • Network egress from your Kubernetes cluster to Teleport.
  • +
  • Helm installed on your local machine.
  • +
  • Kubernetes API access to install the Helm chart.
  • +
    + ); + break; + + case DiscoverGuideId.DatabasePostgres: + case DiscoverGuideId.DatabaseMysql: + overview = ( + + This guide configures mTLS between your Teleport proxy and your target + database. + + ); + prereqs = ( + +
  • + Copy of the database CA certificate if it is signed by a third-party + or private CA. +
  • +
  • + Ability to modify the pg_auth file on the database + server. +
  • +
  • + SSH or tsh access to the server running the database, and ability to + either SCP files, or run a command to retrieve TLS certificates from + the Teleport cluster. +
  • +
    + ); + break; + + case DiscoverGuideId.ServerLinuxAmazon: // TODO (kimlisa) collapse linux and on page info provide supported + case DiscoverGuideId.ServerLinuxDebian: + case DiscoverGuideId.ServerLinuxUbuntu: + case DiscoverGuideId.ServerLinuxRhelCentos: + case DiscoverGuideId.ServerMac: + overview = ( + + This guide sets up a single server in your Teleport cluster for SSH + access. It uses a short-lived, randomly generated{' '} + + join token + {' '} + with Node permissions. It is good for getting quickly started with + server access. + + ); + prereqs = ( + +
  • SSH access to the server.
  • +
  • Root or sudo privileges to run the script.
  • +
  • List of OS users you want to be able to connect as.
  • +
    + ); + break; + + case DiscoverGuideId.KubernetesAwsEks: + links = { + accessEntries: { + title: 'Using access entries', + href: 'https://docs.aws.amazon.com/eks/latest/userguide/setting-up-access-entries.html', + }, + }; + overview = ( + + This guide is used to set up auto-enrollment of one or more EKS + clusters with a script that you will run in AWS CloudShell. + + ); + prereqs = ( + +
  • {requiredAwsAccount}
  • +
  • + + Access entries + {' '} + authentication mode enabled in your target EKS clusters. +
  • +
  • + List of Kubernetes users and groups you want Teleport users to be + able to authenticate as. +
  • +
    + ); + break; + + case DiscoverGuideId.ApplicationAwsCliConsole: + overview = ( + + This guide configures your AWS OIDC policy to allow console access + with a script that you will run in AWS CloudShell. + + ); + prereqs = ( + +
  • {requiredAwsAccount}
  • +
  • List of AWS roles you want to be able to authenticate as.
  • +
    + ); + break; + + case DiscoverGuideId.ServerAwsEc2Ssm: + links = { + systemsFleetManager: { + title: 'AWS Systems/Fleet Manager', + href: 'https://docs.aws.amazon.com/systems-manager/latest/userguide/fleet-manager.html', + }, + ssmAgent: { + title: 'SSM Agent', + href: 'https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-status-and-restart.html', + }, + amazonSSMManagedInstanceCore: { + title: 'AmazonSSMManagedInstanceCore policy', + href: 'https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonSSMManagedInstanceCore.html', + }, + }; + overview = ( + + This guide is used to enroll all EC2 instances controlled by{' '} + + AWS Systems/Fleet Manager + {' '} + in a region. + + ); + prereqs = ( + +
  • {requiredAwsAccount}
  • +
  • + List of OS users you want to be able to connect as (i.e. root, + ubuntu, etc). +
  • +
  • + + SSM Agent + {' '} + running in target EC2 instances, and have the{' '} + + AmazonSSMManagedInstanceCore + {' '} + policy attached to their IAM profile. +
  • +
    + ); + break; + + case DiscoverGuideId.DatabaseAwsRdsAuroraPostgres: + case DiscoverGuideId.DatabaseAwsRdsAuroraMysql: + case DiscoverGuideId.DatabaseAwsRdsPostgres: + case DiscoverGuideId.DatabaseAwsRdsMysqlMariaDb: + links = { + iamAuthn: { + title: 'Creating IAM users', + href: getRdsIamAuthnHref(resourceSpec.id), + }, + amazonEcs: { + title: 'What is Amazon ECS', + href: 'https://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html', + }, + howEnrollmentWorks: { + title: 'How AWS OIDC RDS enrollment work', + href: 'https://goteleport.com/docs/admin-guides/management/guides/awsoidc-integration-rds/', + }, + }; + + overview = ( + + This{' '} + + guide + {' '} + is used to set up enrollment of one or more RDS databases in a region. + A Database Service will be deployed in{' '} + + Amazon ECS + {' '} + that proxies to the databases. + + ); + + prereqs = ( + +
  • {requiredAwsAccount}
  • +
  • + Ability to create database{' '} + + + IAM users + + {' '} + and connect to target databases. +
  • +
  • The VPC of the RDS databases you want to enroll.
  • +
  • + At least one subnet in the VPC with a route to an internet gateway. +
  • +
  • Security groups that allow egress to the Teleport cluster.
  • +
    + ); + break; + default: + return null; + } + + return ( + <> + {overview && <>{overview}} + Prerequisites + {prereqs} + {links && } + + ); +} + +const getRdsIamAuthnHref = ( + id: + | DiscoverGuideId.DatabaseAwsRdsAuroraMysql + | DiscoverGuideId.DatabaseAwsRdsAuroraPostgres + | DiscoverGuideId.DatabaseAwsRdsPostgres + | DiscoverGuideId.DatabaseAwsRdsMysqlMariaDb +) => { + if (id === DiscoverGuideId.DatabaseAwsRdsAuroraMysql) { + return 'https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/UsingWithRDS.IAMDBAuth.DBAccounts.html#UsingWithRDS.IAMDBAuth.DBAccounts.MySQL'; + } + if (id === DiscoverGuideId.DatabaseAwsRdsAuroraPostgres) { + return 'https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/UsingWithRDS.IAMDBAuth.DBAccounts.html#UsingWithRDS.IAMDBAuth.DBAccounts.PostgreSQL'; + } + if (id === DiscoverGuideId.DatabaseAwsRdsPostgres) { + return 'https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.DBAccounts.html#UsingWithRDS.IAMDBAuth.DBAccounts.PostgreSQL'; + } + if (id === DiscoverGuideId.DatabaseAwsRdsMysqlMariaDb) { + return 'https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.DBAccounts.html#UsingWithRDS.IAMDBAuth.DBAccounts.MySQL'; + } +}; diff --git a/web/packages/teleport/src/Discover/Server/DiscoveryConfigSsm/DiscoveryConfigSsm.story.tsx b/web/packages/teleport/src/Discover/Server/DiscoveryConfigSsm/DiscoveryConfigSsm.story.tsx index 08f5d55f73234..4b947988cfd9f 100644 --- a/web/packages/teleport/src/Discover/Server/DiscoveryConfigSsm/DiscoveryConfigSsm.story.tsx +++ b/web/packages/teleport/src/Discover/Server/DiscoveryConfigSsm/DiscoveryConfigSsm.story.tsx @@ -18,28 +18,19 @@ import { delay, http, HttpResponse } from 'msw'; import { useEffect } from 'react'; -import { MemoryRouter } from 'react-router'; import { Info } from 'design/Alert'; -import { ContextProvider } from 'teleport'; import cfg from 'teleport/config'; -import { ServerLocation } from 'teleport/Discover/SelectResource'; -import { ResourceKind } from 'teleport/Discover/Shared'; import { - AutoDiscovery, - DiscoverContextState, - DiscoverProvider, -} from 'teleport/Discover/useDiscover'; -import { createTeleportContext } from 'teleport/mocks/contexts'; + RequiredDiscoverProviders, + resourceSpecAwsEc2Ssm, +} from 'teleport/Discover/Fixtures/fixtures'; +import { AgentMeta, AutoDiscovery } from 'teleport/Discover/useDiscover'; import { IntegrationKind, IntegrationStatusCode, } from 'teleport/services/integrations'; -import { - DiscoverDiscoveryConfigMethod, - DiscoverEventResource, -} from 'teleport/services/userEvent'; import { DiscoveryConfigSsm } from './DiscoveryConfigSsm'; @@ -142,62 +133,30 @@ const Component = ({ }: { autoDiscovery?: AutoDiscovery; }) => { - const ctx = createTeleportContext(); - const discoverCtx: DiscoverContextState = { - agentMeta: { - resourceName: 'aws-console', - agentMatcherLabels: [], - awsIntegration: { - kind: IntegrationKind.AwsOidc, - name: 'some-oidc-name', - resourceType: 'integration', - spec: { - roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', - issuerS3Bucket: '', - issuerS3Prefix: '', - }, - statusCode: IntegrationStatusCode.Running, - }, - autoDiscovery, - }, - currentStep: 0, - nextStep: () => null, - prevStep: () => null, - onSelectResource: () => null, - resourceSpec: { - name: '', - kind: ResourceKind.Application, - icon: null, - keywords: [], - event: DiscoverEventResource.Ec2Instance, - nodeMeta: { - location: ServerLocation.Aws, - discoveryConfigMethod: DiscoverDiscoveryConfigMethod.AwsEc2Ssm, + const agentMeta: AgentMeta = { + resourceName: 'aws-console', + agentMatcherLabels: [], + awsIntegration: { + kind: IntegrationKind.AwsOidc, + name: 'some-oidc-name', + resourceType: 'integration', + spec: { + roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', + issuerS3Bucket: '', + issuerS3Prefix: '', }, + statusCode: IntegrationStatusCode.Running, }, - exitFlow: () => null, - viewConfig: null, - indexedViews: [], - setResourceSpec: () => null, - updateAgentMeta: () => null, - emitErrorEvent: () => null, - emitEvent: () => null, - eventState: null, + autoDiscovery, }; - cfg.proxyCluster = 'localhost'; return ( - - - - Devs: Click next to see next state - - - - + Devs: Click next to see next state + + ); }; diff --git a/web/packages/teleport/src/Discover/Server/DiscoveryConfigSsm/DiscoveryConfigSsm.tsx b/web/packages/teleport/src/Discover/Server/DiscoveryConfigSsm/DiscoveryConfigSsm.tsx index 42d1b89e869b3..05301f280768e 100644 --- a/web/packages/teleport/src/Discover/Server/DiscoveryConfigSsm/DiscoveryConfigSsm.tsx +++ b/web/packages/teleport/src/Discover/Server/DiscoveryConfigSsm/DiscoveryConfigSsm.tsx @@ -94,7 +94,7 @@ export function DiscoveryConfigSsm() { // This can happen if creating discovery config attempt failed // and the user retries. if (!joinTokenRef.current) { - joinTokenRef.current = await joinTokenService.fetchJoinToken({ + joinTokenRef.current = await joinTokenService.fetchJoinTokenV2({ roles: ['Node'], method: 'iam', rules: [{ awsAccountId }], @@ -174,7 +174,7 @@ export function DiscoveryConfigSsm() { } return ( - + <>
    Setup Discovery Config for Teleport Discovery Service
    {cfg.isCloud ? ( @@ -188,9 +188,6 @@ export function DiscoveryConfigSsm() { )} {cfg.isCloud && } - {attempt.status === 'error' && ( - {attempt.statusText} - )}

    Step 1

    @@ -341,12 +338,16 @@ export function DiscoveryConfigSsm() { )} + {attempt.status === 'error' && ( + {attempt.statusText} + )} + - + ); } diff --git a/web/packages/teleport/src/Discover/Server/DownloadScript/DownloadScript.story.tsx b/web/packages/teleport/src/Discover/Server/DownloadScript/DownloadScript.story.tsx index 277c05492f7ac..a2e5a2f206115 100644 --- a/web/packages/teleport/src/Discover/Server/DownloadScript/DownloadScript.story.tsx +++ b/web/packages/teleport/src/Discover/Server/DownloadScript/DownloadScript.story.tsx @@ -18,19 +18,17 @@ import { StoryObj } from '@storybook/react'; import { delay, http, HttpResponse } from 'msw'; -import { MemoryRouter } from 'react-router'; +import { PropsWithChildren } from 'react'; import { withoutQuery } from 'web/packages/build/storybook'; -import { ContextProvider, Context as TeleportContext } from 'teleport'; import cfg from 'teleport/config'; +import { + RequiredDiscoverProviders, + resourceSpecServerLinuxUbuntu, +} from 'teleport/Discover/Fixtures/fixtures'; import { ResourceKind } from 'teleport/Discover/Shared'; -import { PingTeleportProvider } from 'teleport/Discover/Shared/PingTeleportContext'; import { clearCachedJoinTokenResult } from 'teleport/Discover/Shared/useJoinTokenSuspender'; -import { - DiscoverContextState, - DiscoverProvider, -} from 'teleport/Discover/useDiscover'; -import { userContext } from 'teleport/Main/fixtures'; +import { AgentMeta } from 'teleport/Discover/useDiscover'; import { IntegrationKind, IntegrationStatusCode, @@ -39,8 +37,6 @@ import { INTERNAL_RESOURCE_ID_LABEL_KEY, JoinToken, } from 'teleport/services/joinToken'; -import { DiscoverEventResource } from 'teleport/services/userEvent'; -import { UserContextProvider } from 'teleport/User'; import DownloadScript from './DownloadScript'; @@ -169,74 +165,32 @@ export const Failed: StoryObj = { }, }; -const Provider = props => { - const ctx = createTeleportContext(); - const discoverCtx: DiscoverContextState = { - agentMeta: { - awsIntegration: { - kind: IntegrationKind.AwsOidc, - name: 'some-name', - resourceType: 'integration', - spec: { - roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', - issuerS3Bucket: '', - issuerS3Prefix: '', - }, - statusCode: IntegrationStatusCode.Running, - }, +const agentMeta: AgentMeta = { + awsIntegration: { + kind: IntegrationKind.AwsOidc, + name: 'some-name', + resourceType: 'integration', + spec: { + roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', + issuerS3Bucket: '', + issuerS3Prefix: '', }, - currentStep: 0, - nextStep: () => null, - prevStep: () => null, - onSelectResource: () => null, - resourceSpec: { - name: 'kube', - kind: ResourceKind.Kubernetes, - icon: 'kube', - keywords: [], - event: DiscoverEventResource.Kubernetes, - }, - exitFlow: () => null, - viewConfig: null, - indexedViews: [], - setResourceSpec: () => null, - updateAgentMeta: () => null, - emitErrorEvent: () => null, - emitEvent: () => null, - eventState: null, - }; + statusCode: IntegrationStatusCode.Running, + }, +}; +const Provider: React.FC> = props => { return ( - - - - - - {props.children} - - - - - + {props.children} + ); }; -function createTeleportContext() { - const ctx = new TeleportContext(); - - ctx.isEnterprise = false; - ctx.storeUser.setState(userContext); - - return ctx; -} - const joinToken: JoinToken = { id: 'some-id', roles: [], diff --git a/web/packages/teleport/src/Discover/Server/DownloadScript/DownloadScript.tsx b/web/packages/teleport/src/Discover/Server/DownloadScript/DownloadScript.tsx index ec2f0f0e464ae..ddcd1b0e923d3 100644 --- a/web/packages/teleport/src/Discover/Server/DownloadScript/DownloadScript.tsx +++ b/web/packages/teleport/src/Discover/Server/DownloadScript/DownloadScript.tsx @@ -285,7 +285,7 @@ export function StepTwoWithActionBtns( lines={[{ text: createBashCommand(joinToken.id) }]} /> - {hint} + {hint} )} - - - - - + + + + + + + ); diff --git a/web/packages/teleport/src/Discover/Server/SetupAccess/SetupAccess.story.tsx b/web/packages/teleport/src/Discover/Server/SetupAccess/SetupAccess.story.tsx index 56d3454dafc5c..fe898757b7d27 100644 --- a/web/packages/teleport/src/Discover/Server/SetupAccess/SetupAccess.story.tsx +++ b/web/packages/teleport/src/Discover/Server/SetupAccess/SetupAccess.story.tsx @@ -18,6 +18,7 @@ import { MemoryRouter } from 'react-router'; +import { DiscoverBox } from 'teleport/Discover/Shared'; import { initSelectedOptionsHelper, type State, @@ -31,25 +32,33 @@ export default { export const NoTraits = () => ( - []} /> + + []} /> + ); export const WithTraits = () => ( - + + + ); export const NoAccess = () => ( - + + + ); export const SsoUser = () => ( - + + + ); diff --git a/web/packages/teleport/src/Discover/Server/Shared.tsx b/web/packages/teleport/src/Discover/Server/Shared.tsx index f113371fe433f..3b8beb5854523 100644 --- a/web/packages/teleport/src/Discover/Server/Shared.tsx +++ b/web/packages/teleport/src/Discover/Server/Shared.tsx @@ -19,12 +19,12 @@ import { Link as InternalLink } from 'react-router-dom'; import { Mark } from 'design'; -import { OutlineInfo } from 'design/Alert/Alert'; +import { Info } from 'design/Alert/Alert'; import cfg from 'teleport/config'; export const SingleEc2InstanceInstallation = () => ( - + Auto discovery will enroll all EC2 instances found in a region. If you want to enroll a single EC2 instance instead, consider following the{' '} ( Teleport service installation {' '} flow. - + ); diff --git a/web/packages/teleport/src/Discover/Server/TestConnection/TestConnection.story.tsx b/web/packages/teleport/src/Discover/Server/TestConnection/TestConnection.story.tsx index da5bc32f43c0e..db6c61a3f6a3d 100644 --- a/web/packages/teleport/src/Discover/Server/TestConnection/TestConnection.story.tsx +++ b/web/packages/teleport/src/Discover/Server/TestConnection/TestConnection.story.tsx @@ -16,15 +16,10 @@ * along with this program. If not, see . */ -import { MemoryRouter } from 'react-router'; - -import { ContextProvider } from 'teleport'; -import cfg from 'teleport/config'; import { - DiscoverContextState, - DiscoverProvider, -} from 'teleport/Discover/useDiscover'; -import { createTeleportContext } from 'teleport/mocks/contexts'; + RequiredDiscoverProviders, + resourceSpecServerLinuxUbuntu, +} from 'teleport/Discover/Fixtures/fixtures'; import { nodes } from 'teleport/Nodes/fixtures'; import { TestConnection } from './TestConnection'; @@ -51,31 +46,12 @@ export const Init = () => ( ); const Provider = ({ children }) => { - const ctx = createTeleportContext(); - const discoverCtx: DiscoverContextState = { - ...agentStepProps, - currentStep: 0, - onSelectResource: () => null, - resourceSpec: undefined, - exitFlow: () => null, - viewConfig: null, - indexedViews: [], - setResourceSpec: () => null, - updateAgentMeta: () => null, - emitErrorEvent: () => null, - emitEvent: () => null, - eventState: null, - }; - return ( - - - {children} - - + {children} + ); }; diff --git a/web/packages/teleport/src/Discover/Server/TestConnection/TestConnection.tsx b/web/packages/teleport/src/Discover/Server/TestConnection/TestConnection.tsx index a235bc8b40196..ab1c3c24bb6c4 100644 --- a/web/packages/teleport/src/Discover/Server/TestConnection/TestConnection.tsx +++ b/web/packages/teleport/src/Discover/Server/TestConnection/TestConnection.tsx @@ -82,7 +82,7 @@ export function TestConnection(props: AgentStepProps) { const [selectedOpt, setSelectedOpt] = useState(usernameOpts[0]); return ( - + <> {showMfaDialog && ( testConnection(selectedOpt.value, res)} @@ -131,6 +131,6 @@ export function TestConnection(props: AgentStepProps) { - + ); } diff --git a/web/packages/teleport/src/Discover/Shared/AwsAccount/AwsAccount.story.tsx b/web/packages/teleport/src/Discover/Shared/AwsAccount/AwsAccount.story.tsx index 96f779476b8e1..97c1795299f9f 100644 --- a/web/packages/teleport/src/Discover/Shared/AwsAccount/AwsAccount.story.tsx +++ b/web/packages/teleport/src/Discover/Shared/AwsAccount/AwsAccount.story.tsx @@ -17,14 +17,10 @@ */ import { delay, http, HttpResponse } from 'msw'; -import { MemoryRouter } from 'react-router'; -import { ContextProvider } from 'teleport'; import cfg from 'teleport/config'; -import { - DiscoverContextState, - DiscoverProvider, -} from 'teleport/Discover/useDiscover'; +import { resourceSpecAwsRdsPostgres } from 'teleport/Discover/Fixtures/databases'; +import { RequiredDiscoverProviders } from 'teleport/Discover/Fixtures/fixtures'; import { createTeleportContext, getAcl } from 'teleport/mocks/contexts'; import { AwsAccount } from './AwsAccount'; @@ -70,7 +66,7 @@ export const Failed = () => ; Failed.parameters = { msw: { handlers: [ - http.post(cfg.getIntegrationsUrl(), () => + http.get(cfg.getIntegrationsUrl(), () => HttpResponse.json( { message: 'some kind of error', @@ -87,35 +83,14 @@ export const NoPerm = () => ; const Component = ({ noAccess = false }: { noAccess?: boolean }) => { const ctx = createTeleportContext(); ctx.storeUser.state.acl = getAcl({ noAccess }); - const discoverCtx: DiscoverContextState = { - agentMeta: {}, - currentStep: 0, - nextStep: () => null, - prevStep: () => null, - onSelectResource: () => null, - resourceSpec: {} as any, - exitFlow: () => null, - viewConfig: null, - indexedViews: [], - setResourceSpec: () => null, - updateAgentMeta: () => null, - emitErrorEvent: () => null, - emitEvent: () => null, - eventState: null, - }; - cfg.proxyCluster = 'localhost'; return ( - - - - - - - + + ); }; diff --git a/web/packages/teleport/src/Discover/Shared/AwsAccount/AwsAccount.test.tsx b/web/packages/teleport/src/Discover/Shared/AwsAccount/AwsAccount.test.tsx index bc2208f3feabd..2ae72e91c5aef 100644 --- a/web/packages/teleport/src/Discover/Shared/AwsAccount/AwsAccount.test.tsx +++ b/web/packages/teleport/src/Discover/Shared/AwsAccount/AwsAccount.test.tsx @@ -16,19 +16,16 @@ * along with this program. If not, see . */ -import { MemoryRouter } from 'react-router'; - import { fireEvent, render, screen } from 'design/utils/testing'; -import { ContextProvider } from 'teleport'; -import cfg from 'teleport/config'; import { app } from 'teleport/Discover/AwsMangementConsole/fixtures'; -import { ResourceSpec } from 'teleport/Discover/SelectResource'; import { - DiscoverContextState, - DiscoverProvider, -} from 'teleport/Discover/useDiscover'; -import { FeaturesContextProvider } from 'teleport/FeaturesContext'; + RequiredDiscoverProviders, + resourceSpecAppAwsCliConsole, + resourceSpecServerLinuxUbuntu, +} from 'teleport/Discover/Fixtures/fixtures'; +import { SelectResourceSpec } from 'teleport/Discover/SelectResource/resources'; +import { DiscoverContextState } from 'teleport/Discover/useDiscover'; import { createTeleportContext, getAcl } from 'teleport/mocks/contexts'; import { IntegrationKind, @@ -36,13 +33,9 @@ import { IntegrationStatusCode, } from 'teleport/services/integrations'; import ResourceService from 'teleport/services/resources'; -import { - DiscoverEventResource, - userEventService, -} from 'teleport/services/userEvent'; +import { userEventService } from 'teleport/services/userEvent'; import TeleportContext from 'teleport/teleportContext'; -import { ResourceKind } from '../ResourceKind'; import { AwsAccount } from './AwsAccount'; beforeEach(() => { @@ -74,13 +67,7 @@ afterEach(() => { }); test('non application resource kind', async () => { - const { ctx, discoverCtx } = getMockedContexts({ - kind: ResourceKind.Server, - name: '', - icon: undefined, - keywords: [], - event: DiscoverEventResource.Server, - }); + const { ctx, discoverCtx } = getMockedContexts(resourceSpecServerLinuxUbuntu); renderAwsAccount(ctx, discoverCtx); await screen.findByText(/aws Integrations/i); @@ -93,14 +80,7 @@ test('non application resource kind', async () => { }); test('with application resource kind for aws console', async () => { - const { ctx, discoverCtx } = getMockedContexts({ - kind: ResourceKind.Application, - appMeta: { awsConsole: true }, - name: '', - icon: undefined, - keywords: [], - event: DiscoverEventResource.ApplicationHttp, - }); + const { ctx, discoverCtx } = getMockedContexts(resourceSpecAppAwsCliConsole); renderAwsAccount(ctx, discoverCtx); await screen.findByText(/aws Integrations/i); @@ -113,14 +93,7 @@ test('with application resource kind for aws console', async () => { }); test('missing permissions for integrations', async () => { - const { ctx, discoverCtx } = getMockedContexts({ - kind: ResourceKind.Application, - appMeta: { awsConsole: true }, - name: '', - icon: undefined, - keywords: [], - event: DiscoverEventResource.ApplicationHttp, - }); + const { ctx, discoverCtx } = getMockedContexts(resourceSpecAppAwsCliConsole); ctx.storeUser.state.acl = getAcl({ noAccess: true }); @@ -143,14 +116,9 @@ test('missing permissions for integrations', async () => { }); test('health check is called after selecting an aws integration', async () => { - const { ctx, discoverCtx, spyPing } = getMockedContexts({ - kind: ResourceKind.Application, - appMeta: { awsConsole: true }, - name: '', - icon: undefined, - keywords: [], - event: DiscoverEventResource.ApplicationHttp, - }); + const { ctx, discoverCtx, spyPing } = getMockedContexts( + resourceSpecAppAwsCliConsole + ); renderAwsAccount(ctx, discoverCtx); @@ -163,7 +131,7 @@ test('health check is called after selecting an aws integration', async () => { expect(spyPing).toHaveBeenCalledTimes(1); }); -function getMockedContexts(resourceSpec: ResourceSpec) { +function getMockedContexts(resourceSpec: SelectResourceSpec) { const ctx = createTeleportContext(); const discoverCtx: DiscoverContextState = { agentMeta: {}, @@ -208,18 +176,13 @@ function renderAwsAccount( discoverCtx: DiscoverContextState ) { return render( - - - - - - - - - + + ); } diff --git a/web/packages/teleport/src/Discover/Shared/AwsAccount/AwsAccount.tsx b/web/packages/teleport/src/Discover/Shared/AwsAccount/AwsAccount.tsx index c349468b94cb7..82254f647a373 100644 --- a/web/packages/teleport/src/Discover/Shared/AwsAccount/AwsAccount.tsx +++ b/web/packages/teleport/src/Discover/Shared/AwsAccount/AwsAccount.tsx @@ -161,9 +161,9 @@ export function AwsAccount() { if (!hasAccess) { return ( - + <> - + You don’t have the permissions required to set up this integration.
    @@ -179,30 +179,30 @@ export function AwsAccount() {
    -
    + ); } if (attempt.status === '' || attempt.status === 'processing') { return ( - + <> - + ); } if (attempt.status === 'error') { return ( - + <> - + {attempt.statusText} Retry - + ); } @@ -267,7 +267,7 @@ export function AwsAccount() { } as DiscoverUrlLocationState, }; return ( - + <> {healthCheckAttempt.status === 'error' && ( -
    + ); } diff --git a/web/packages/teleport/src/Discover/Shared/ConfigureDiscoveryService/ConfigureDiscoveryService.story.tsx b/web/packages/teleport/src/Discover/Shared/ConfigureDiscoveryService/ConfigureDiscoveryService.story.tsx index d53d6afeac44c..1adea78c25e68 100644 --- a/web/packages/teleport/src/Discover/Shared/ConfigureDiscoveryService/ConfigureDiscoveryService.story.tsx +++ b/web/packages/teleport/src/Discover/Shared/ConfigureDiscoveryService/ConfigureDiscoveryService.story.tsx @@ -17,27 +17,21 @@ */ import { http, HttpResponse } from 'msw'; -import { MemoryRouter } from 'react-router'; import { Info } from 'design/Alert'; -import { ContextProvider } from 'teleport'; import cfg from 'teleport/config'; -import { ServerLocation } from 'teleport/Discover/SelectResource'; -import { ResourceKind } from 'teleport/Discover/Shared'; +import { resourceSpecAwsRdsPostgres } from 'teleport/Discover/Fixtures/databases'; import { - DiscoverContextState, - DiscoverProvider, -} from 'teleport/Discover/useDiscover'; -import { createTeleportContext } from 'teleport/mocks/contexts'; + RequiredDiscoverProviders, + resourceSpecAwsEc2Ssm, +} from 'teleport/Discover/Fixtures/fixtures'; +import { SelectResourceSpec } from 'teleport/Discover/SelectResource/resources'; +import { AgentMeta } from 'teleport/Discover/useDiscover'; import { IntegrationKind, IntegrationStatusCode, } from 'teleport/services/integrations'; -import { - DiscoverDiscoveryConfigMethod, - DiscoverEventResource, -} from 'teleport/services/userEvent'; import { ConfigureDiscoveryService as Comp } from './ConfigureDiscoveryService'; @@ -46,15 +40,20 @@ export default { }; export const Server = () => { - return ; + return ; }; export const Database = () => { - return ; + return ; }; export const WithCreateConfig = () => { - return ; + return ( + + ); }; WithCreateConfig.parameters = { msw: { @@ -65,7 +64,12 @@ WithCreateConfig.parameters = { }; export const WithCreateConfigFailed = () => { - return ; + return ( + + ); }; WithCreateConfigFailed.parameters = { msw: { @@ -87,77 +91,44 @@ WithCreateConfigFailed.parameters = { }; const Component = ({ - kind, + resourceSpec, withCreateConfig = false, }: { - kind: ResourceKind; + resourceSpec: SelectResourceSpec; withCreateConfig?: boolean; }) => { - const ctx = createTeleportContext(); - const discoverCtx: DiscoverContextState = { - agentMeta: { - resourceName: 'aws-console', - agentMatcherLabels: [], - awsRegion: 'ap-south-1', - awsIntegration: { - kind: IntegrationKind.AwsOidc, - name: 'some-oidc-name', - resourceType: 'integration', - spec: { - roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', - issuerS3Bucket: '', - issuerS3Prefix: '', - }, - statusCode: IntegrationStatusCode.Running, - }, - autoDiscovery: { - config: { - name: 'discovery-config-name', - discoveryGroup: 'discovery-group-name', - aws: [], - }, + const agentMeta: AgentMeta = { + resourceName: 'aws-console', + agentMatcherLabels: [], + awsRegion: 'ap-south-1', + awsIntegration: { + kind: IntegrationKind.AwsOidc, + name: 'some-oidc-name', + resourceType: 'integration', + spec: { + roleArn: 'arn:aws:iam::123456789012:role/test-role-arn', + issuerS3Bucket: '', + issuerS3Prefix: '', }, + statusCode: IntegrationStatusCode.Running, }, - currentStep: 0, - nextStep: () => null, - prevStep: () => null, - onSelectResource: () => null, - resourceSpec: { - name: '', - kind, - icon: null, - keywords: [], - event: DiscoverEventResource.Ec2Instance, - nodeMeta: { - location: ServerLocation.Aws, - discoveryConfigMethod: DiscoverDiscoveryConfigMethod.AwsEc2Ssm, + autoDiscovery: { + config: { + name: 'discovery-config-name', + discoveryGroup: 'discovery-group-name', + aws: [], }, }, - exitFlow: () => null, - viewConfig: null, - indexedViews: [], - setResourceSpec: () => null, - updateAgentMeta: () => null, - emitErrorEvent: () => null, - emitEvent: () => null, - eventState: null, }; - - cfg.proxyCluster = 'localhost'; return ( - - - - {withCreateConfig && ( - Devs: Click next to see create config dialog - )} - - - - + {withCreateConfig && ( + Devs: Click next to see create config dialog + )} + + ); }; diff --git a/web/packages/teleport/src/Discover/Shared/ConfigureDiscoveryService/ConfigureDiscoveryService.tsx b/web/packages/teleport/src/Discover/Shared/ConfigureDiscoveryService/ConfigureDiscoveryService.tsx index 32f7b9590bcb6..059486915461b 100644 --- a/web/packages/teleport/src/Discover/Shared/ConfigureDiscoveryService/ConfigureDiscoveryService.tsx +++ b/web/packages/teleport/src/Discover/Shared/ConfigureDiscoveryService/ConfigureDiscoveryService.tsx @@ -19,8 +19,8 @@ import { useState } from 'react'; import { Link as InternalLink } from 'react-router-dom'; -import { Box, Mark, Text } from 'design'; -import { OutlineInfo } from 'design/Alert/Alert'; +import { Mark, Text } from 'design'; +import { Info } from 'design/Alert/Alert'; import useAttempt from 'shared/hooks/useAttemptNext'; import { getErrMessage } from 'shared/utils/errorType'; @@ -117,7 +117,7 @@ export function ConfigureDiscoveryService({ } return ( - + <>
    Configure Teleport Discovery Service
    )} -
    + ); } @@ -158,7 +158,7 @@ function EnrollInfo({ kind }: { kind: ResourceKind }) { The Teleport Discovery Service can connect to Amazon EC2 and automatically discover and enroll EC2 instances. - + Auto discovery will enroll all EC2 instances found in a region. If you want to enroll a single EC2 instance instead, consider following{' '} @@ -171,7 +171,7 @@ function EnrollInfo({ kind }: { kind: ResourceKind }) { the Teleport service installation flow . - + ); } diff --git a/web/packages/teleport/src/Discover/Shared/SetupAccess/SetupAccessWrapper.tsx b/web/packages/teleport/src/Discover/Shared/SetupAccess/SetupAccessWrapper.tsx index 9d020f025bb6b..fcca7c2fa400d 100644 --- a/web/packages/teleport/src/Discover/Shared/SetupAccess/SetupAccessWrapper.tsx +++ b/web/packages/teleport/src/Discover/Shared/SetupAccess/SetupAccessWrapper.tsx @@ -17,7 +17,6 @@ */ import React from 'react'; -import styled from 'styled-components'; import { Box, Flex, Indicator } from 'design'; import * as Icons from 'design/Icon'; @@ -28,6 +27,7 @@ import { ButtonBlueText, Header, HeaderSubtitle, + StyledBox, } from 'teleport/Discover/Shared'; import { AccessInfo, type TraitKind } from './AccessInfo'; @@ -138,7 +138,7 @@ export function SetupAccessWrapper({ const ssoUserWithAutoDiscover = wantAutoDiscover && isSsoUser; return ( - + <>
    Set Up Access
    {headerSubtitle} {preContent} @@ -161,13 +161,6 @@ export function SetupAccessWrapper({ (!ssoUserWithAutoDiscover && !hasTraits) } /> -
    + ); } - -const StyledBox = styled(Box)` - max-width: 700px; - background-color: ${props => props.theme.colors.spotBackground[0]}; - border-radius: 8px; - padding: 20px; -`; diff --git a/web/packages/teleport/src/Discover/Shared/SetupAccess/useUserTraits.test.tsx b/web/packages/teleport/src/Discover/Shared/SetupAccess/useUserTraits.test.tsx index b38b48abc9de8..4a7ec7e4b8c91 100644 --- a/web/packages/teleport/src/Discover/Shared/SetupAccess/useUserTraits.test.tsx +++ b/web/packages/teleport/src/Discover/Shared/SetupAccess/useUserTraits.test.tsx @@ -17,26 +17,29 @@ */ import { act, renderHook, waitFor } from '@testing-library/react'; -import { MemoryRouter } from 'react-router'; import { AwsRole } from 'shared/services/apps'; -import { ContextProvider } from 'teleport'; -import cfg from 'teleport/config'; import { app } from 'teleport/Discover/AwsMangementConsole/fixtures'; import { - defaultDiscoverContext, - defaultResourceSpec, + resourceSpecAwsRdsPostgres, + resourceSpecSelfHostedPostgres, +} from 'teleport/Discover/Fixtures/databases'; +import { + emptyDiscoverContext, + RequiredDiscoverProviders, + resourceSpecAppAwsCliConsole, + resourceSpecAwsEc2Ssm, + resourceSpecSelfHostedKube, + resourceSpecServerLinuxUbuntu, } from 'teleport/Discover/Fixtures/fixtures'; import { - DiscoverProvider, type AppMeta, type DbMeta, type DiscoverContextState, type KubeMeta, type NodeMeta, } from 'teleport/Discover/useDiscover'; -import { FeaturesContextProvider } from 'teleport/FeaturesContext'; import { createTeleportContext } from 'teleport/mocks/contexts'; import { ExcludeUserField } from 'teleport/services/user'; import { userEventService } from 'teleport/services/userEvent'; @@ -59,8 +62,8 @@ describe('onProceed correctly deduplicates, removes static traits, updates meta, }); test('kubernetes', async () => { - const discoverCtx = defaultDiscoverContext({ - resourceSpec: defaultResourceSpec(ResourceKind.Kubernetes), + const discoverCtx = emptyDiscoverContext({ + resourceSpec: resourceSpecSelfHostedKube, }); discoverCtx.nextStep = jest.fn(); discoverCtx.agentMeta = { @@ -150,8 +153,8 @@ describe('onProceed correctly deduplicates, removes static traits, updates meta, }); test('kubernetes with auto discover preserves existing + new dynamic traits', async () => { - const discoverCtx = defaultDiscoverContext({ - resourceSpec: defaultResourceSpec(ResourceKind.Kubernetes), + const discoverCtx = emptyDiscoverContext({ + resourceSpec: resourceSpecSelfHostedKube, }); discoverCtx.nextStep = jest.fn(); discoverCtx.agentMeta = { @@ -234,8 +237,8 @@ describe('onProceed correctly deduplicates, removes static traits, updates meta, }); test('database', async () => { - const discoverCtx = defaultDiscoverContext({ - resourceSpec: defaultResourceSpec(ResourceKind.Database), + const discoverCtx = emptyDiscoverContext({ + resourceSpec: resourceSpecSelfHostedPostgres, }); discoverCtx.nextStep = jest.fn(); discoverCtx.agentMeta = { @@ -321,8 +324,8 @@ describe('onProceed correctly deduplicates, removes static traits, updates meta, }); test('database with auto discover preserves existing + new dynamic traits', async () => { - const discoverCtx = defaultDiscoverContext({ - resourceSpec: defaultResourceSpec(ResourceKind.Database), + const discoverCtx = emptyDiscoverContext({ + resourceSpec: resourceSpecSelfHostedPostgres, }); discoverCtx.nextStep = jest.fn(); discoverCtx.agentMeta = { @@ -394,8 +397,8 @@ describe('onProceed correctly deduplicates, removes static traits, updates meta, }); test('node', async () => { - const discoverCtx = defaultDiscoverContext({ - resourceSpec: defaultResourceSpec(ResourceKind.Server), + const discoverCtx = emptyDiscoverContext({ + resourceSpec: resourceSpecServerLinuxUbuntu, }); discoverCtx.nextStep = jest.fn(); discoverCtx.agentMeta = { @@ -483,11 +486,8 @@ describe('onProceed correctly deduplicates, removes static traits, updates meta, accountId: '123456789012', }, ]; - const discoverCtx = defaultDiscoverContext({ - resourceSpec: { - ...defaultResourceSpec(ResourceKind.Application), - appMeta: { awsConsole: true }, - }, + const discoverCtx = emptyDiscoverContext({ + resourceSpec: resourceSpecAppAwsCliConsole, agentMeta: { app: { ...app, @@ -566,8 +566,8 @@ describe('onProceed correctly deduplicates, removes static traits, updates meta, }); test('node with auto discover preserves existing + new dynamic traits', async () => { - const discoverCtx = defaultDiscoverContext({ - resourceSpec: defaultResourceSpec(ResourceKind.Server), + const discoverCtx = emptyDiscoverContext({ + resourceSpec: resourceSpecAwsEc2Ssm, }); discoverCtx.nextStep = jest.fn(); discoverCtx.agentMeta = { @@ -629,20 +629,20 @@ describe('onProceed correctly deduplicates, removes static traits, updates meta, describe('static and dynamic traits are correctly separated and correctly creates Option objects', () => { test.each` - resourceKind | traitName - ${ResourceKind.Kubernetes} | ${'kubeUsers'} - ${ResourceKind.Kubernetes} | ${'kubeGroups'} - ${ResourceKind.Server} | ${'logins'} - ${ResourceKind.Database} | ${'databaseNames'} - ${ResourceKind.Database} | ${'databaseUsers'} - `('$traitName', async ({ resourceKind, traitName }) => { + resourceKind | resourceSpec | traitName + ${ResourceKind.Kubernetes} | ${resourceSpecSelfHostedKube} | ${'kubeUsers'} + ${ResourceKind.Kubernetes} | ${resourceSpecSelfHostedKube} | ${'kubeGroups'} + ${ResourceKind.Server} | ${resourceSpecServerLinuxUbuntu} | ${'logins'} + ${ResourceKind.Database} | ${resourceSpecSelfHostedPostgres} | ${'databaseNames'} + ${ResourceKind.Database} | ${resourceSpecSelfHostedPostgres} | ${'databaseUsers'} + `('$traitName', async ({ resourceKind, resourceSpec, traitName }) => { const teleCtx = createTeleportContext(); jest .spyOn(teleCtx.userService, 'fetchUser') .mockResolvedValue(getMockUser()); - const discoverCtx = defaultDiscoverContext({ - resourceSpec: defaultResourceSpec(resourceKind), + const discoverCtx = emptyDiscoverContext({ + resourceSpec, }); discoverCtx.nextStep = jest.fn(); discoverCtx.agentMeta = { @@ -728,8 +728,8 @@ describe('calls to nextStep respects number of steps to skip', () => { jest.spyOn(teleCtx.userService, 'fetchUser').mockResolvedValue(user); - const discoverCtx = defaultDiscoverContext({ - resourceSpec: defaultResourceSpec(ResourceKind.Database), + const discoverCtx = emptyDiscoverContext({ + resourceSpec: resourceSpecAwsRdsPostgres, }); discoverCtx.nextStep = jest.fn(); discoverCtx.agentMeta.autoDiscovery = { @@ -839,12 +839,13 @@ function wrapperFn( teleportCtx: TeleportContext ) { return ({ children }) => ( - - - - {children} - - - + + {children} + ); } diff --git a/web/packages/teleport/src/Discover/Shared/StyledBox.ts b/web/packages/teleport/src/Discover/Shared/StyledBox.ts index 8b047efde9459..8f348e2f15975 100644 --- a/web/packages/teleport/src/Discover/Shared/StyledBox.ts +++ b/web/packages/teleport/src/Discover/Shared/StyledBox.ts @@ -20,10 +20,16 @@ import styled from 'styled-components'; import { Box } from 'design'; -export const StyledBox = styled(Box).attrs({ +const maxWidth = 880; + +export const DiscoverBox = styled(Box).attrs({ + maxWidth: `${maxWidth}px`, + width: '100%', +})``; + +export const StyledBox = styled(DiscoverBox).attrs({ p: 4, borderRadius: 3, - maxWidth: '800px', })` background-color: ${props => props.theme.colors.spotBackground[0]}; `; diff --git a/web/packages/teleport/src/Discover/Shared/index.ts b/web/packages/teleport/src/Discover/Shared/index.ts index 849bca766a56a..3ccb5b173d745 100644 --- a/web/packages/teleport/src/Discover/Shared/index.ts +++ b/web/packages/teleport/src/Discover/Shared/index.ts @@ -45,6 +45,6 @@ export { RadioCell, StatusCell, } from './Aws'; -export { StyledBox } from './StyledBox'; +export { StyledBox, DiscoverBox } from './StyledBox'; export type { DiscoverLabel } from './LabelsCreater'; diff --git a/web/packages/teleport/src/Discover/Shared/useJoinTokenSuspender.test.tsx b/web/packages/teleport/src/Discover/Shared/useJoinTokenSuspender.test.tsx index 682edf971a2de..95286c9c9b6b1 100644 --- a/web/packages/teleport/src/Discover/Shared/useJoinTokenSuspender.test.tsx +++ b/web/packages/teleport/src/Discover/Shared/useJoinTokenSuspender.test.tsx @@ -17,17 +17,16 @@ */ import { renderHook, waitFor } from '@testing-library/react'; -import { MemoryRouter } from 'react-router'; -import { ContextProvider } from 'teleport/index'; -import { - DiscoverEventResource, - userEventService, -} from 'teleport/services/userEvent'; +import { userEventService } from 'teleport/services/userEvent'; import { ProxyRequiresUpgrade } from 'teleport/services/version/unsupported'; import TeleportContext from 'teleport/teleportContext'; -import { DiscoverContextState, DiscoverProvider } from '../useDiscover'; +import { + RequiredDiscoverProviders, + resourceSpecAwsEks, +} from '../Fixtures/fixtures'; +import { DiscoverContextState } from '../useDiscover'; import { ResourceKind } from './ResourceKind'; import { clearCachedJoinTokenResult, @@ -57,11 +56,14 @@ test('create join token without labels', async () => { .mockResolvedValue(tokenResp); const wrapper = ({ children }) => ( - - - {children} - - + + {children} + ); let { result } = renderHook( @@ -90,11 +92,14 @@ test('create join token without labels with v1 fallback', async () => { .mockResolvedValue(tokenResp); const wrapper = ({ children }) => ( - - - {children} - - + + {children} + ); let { result } = renderHook( @@ -121,13 +126,7 @@ const discoverCtx: DiscoverContextState = { nextStep: () => null, prevStep: () => null, onSelectResource: () => null, - resourceSpec: { - name: 'Eks', - kind: ResourceKind.Kubernetes, - icon: 'eks', - keywords: [], - event: DiscoverEventResource.KubernetesEks, - }, + resourceSpec: resourceSpecAwsEks, exitFlow: () => null, viewConfig: null, indexedViews: [], diff --git a/web/packages/teleport/src/Discover/useDiscover.test.tsx b/web/packages/teleport/src/Discover/useDiscover.test.tsx index 70aadf7ae2cd4..52e7723a3e8f4 100644 --- a/web/packages/teleport/src/Discover/useDiscover.test.tsx +++ b/web/packages/teleport/src/Discover/useDiscover.test.tsx @@ -17,12 +17,7 @@ */ import { act, renderHook } from '@testing-library/react'; -import { MemoryRouter } from 'react-router'; -import { ContextProvider } from 'teleport'; -import cfg from 'teleport/config'; -import { FeaturesContextProvider } from 'teleport/FeaturesContext'; -import { createTeleportContext } from 'teleport/mocks/contexts'; import api from 'teleport/services/api'; import { DiscoverEvent, @@ -33,11 +28,11 @@ import { userEventService, } from 'teleport/services/userEvent'; +import { RequiredDiscoverProviders } from './Fixtures/fixtures'; import { SERVERS } from './SelectResource/resources'; -import { DiscoverProvider, useDiscover } from './useDiscover'; +import { useDiscover } from './useDiscover'; describe('emitting events', () => { - const ctx = createTeleportContext(); let wrapper; beforeEach(() => { @@ -47,13 +42,9 @@ describe('emitting events', () => { .mockResolvedValue(null as never); // return value does not matter but required by ts wrapper = ({ children }) => ( - - - - {children} - - - + + {children} + ); }); diff --git a/web/packages/teleport/src/Discover/useDiscover.tsx b/web/packages/teleport/src/Discover/useDiscover.tsx index 5d1775225cffa..3c60fbb5f7efb 100644 --- a/web/packages/teleport/src/Discover/useDiscover.tsx +++ b/web/packages/teleport/src/Discover/useDiscover.tsx @@ -24,6 +24,7 @@ import { findViewAtIndex, } from 'teleport/components/Wizard/flow'; import cfg from 'teleport/config'; +import { useInfoGuide } from 'teleport/Main/InfoGuideContext'; import type { ResourceLabel } from 'teleport/services/agents'; import type { App } from 'teleport/services/apps'; import type { Database } from 'teleport/services/databases'; @@ -54,8 +55,9 @@ import { import { ServiceDeployMethod } from './Database/common'; import { ResourceViewConfig, View } from './flow'; +import { getOverview } from './Overview/Overview'; import { viewConfigs } from './resourceViewConfigs'; -import type { ResourceSpec } from './SelectResource'; +import { SelectResourceSpec } from './SelectResource/resources'; import { EViewConfigs } from './types'; export interface DiscoverContextState { @@ -63,9 +65,9 @@ export interface DiscoverContextState { currentStep: number; nextStep: (count?: number) => void; prevStep: () => void; - onSelectResource: (resource: ResourceSpec) => void; + onSelectResource: (resource: SelectResourceSpec) => void; exitFlow: () => void; - resourceSpec: ResourceSpec; + resourceSpec: SelectResourceSpec; viewConfig: ResourceViewConfig; indexedViews: View[]; setResourceSpec: (value: T) => void; @@ -95,7 +97,7 @@ type CustomEventInput = { export type DiscoverUpdateProps = { // resourceSpec specifies ResourceSpec which should be used to // start a Discover flow. - resourceSpec: ResourceSpec; + resourceSpec: SelectResourceSpec; // agentMeta includes data that will be used to prepopulate input fields // in the respective Discover compnents. agentMeta: AgentMeta; @@ -119,7 +121,7 @@ export type DiscoverUrlLocationState = { // the flow from where user left off. discover: { eventState: EventState; - resourceSpec: ResourceSpec; + resourceSpec: SelectResourceSpec; currentStep: number; }; // integration is the created aws-oidc integration @@ -136,10 +138,11 @@ export function DiscoverProvider({ }: React.PropsWithChildren) { const history = useHistory(); const location = useLocation(); + const { infoGuideElement, setInfoGuideElement } = useInfoGuide(); const [currentStep, setCurrentStep] = useState(0); const [agentMeta, setAgentMeta] = useState(); - const [resourceSpec, setResourceSpec] = useState(); + const [resourceSpec, setResourceSpec] = useState(); const [viewConfig, setViewConfig] = useState(); const [eventState, setEventState] = useState({} as any); @@ -291,7 +294,7 @@ export function DiscoverProvider({ // onSelectResources inits states, starts flow, and // emits events. - function onSelectResource(resource: ResourceSpec) { + function onSelectResource(resource: SelectResourceSpec) { // We still want to emit an event if user clicked on an // unguided link to gather data on which unguided resource // is most popular. @@ -323,7 +326,7 @@ export function DiscoverProvider({ // startDiscoverFlow sets all the required states // that will begin the flow. function startDiscoverFlow( - resource: ResourceSpec, + resource: SelectResourceSpec, initEventState: EventState, targetViewIndex = 0 ) { @@ -354,6 +357,7 @@ export function DiscoverProvider({ setIndexedViews(indexedViews); setResourceSpec(resource); setCurrentStep(targetViewIndex); + setInfoGuideElement(getOverview({ resourceSpec: resource })); } // nextStep takes the user to next screen and sends reporting events. @@ -439,6 +443,10 @@ export function DiscoverProvider({ setViewConfig(null); setResourceSpec(null); setIndexedViews([]); + + if (infoGuideElement) { + setInfoGuideElement(null); + } } function updateAgentMeta(meta: AgentMeta) { diff --git a/web/packages/teleport/src/JoinTokens/JoinTokens.story.tsx b/web/packages/teleport/src/JoinTokens/JoinTokens.story.tsx index 8e9ef4c8003d7..55ef629649987 100644 --- a/web/packages/teleport/src/JoinTokens/JoinTokens.story.tsx +++ b/web/packages/teleport/src/JoinTokens/JoinTokens.story.tsx @@ -17,11 +17,9 @@ */ import { http, HttpResponse } from 'msw'; -import { MemoryRouter } from 'react-router'; -import { ContextProvider } from 'teleport'; import cfg from 'teleport/config'; -import { createTeleportContext } from 'teleport/mocks/contexts'; +import { TeleportProviderBasic } from 'teleport/mocks/providers'; import { JoinToken } from 'teleport/services/joinToken'; import { JoinTokens } from './JoinTokens'; @@ -31,9 +29,9 @@ export default { }; export const Loaded = () => ( - + - + ); Loaded.parameters = { @@ -49,16 +47,6 @@ Loaded.parameters = { }, }; -const Provider = ({ children }) => { - const ctx = createTeleportContext(); - - return ( - - {children} - - ); -}; - const tokens: JoinToken[] = [ { id: 'token1', diff --git a/web/packages/teleport/src/Roles/Roles.story.tsx b/web/packages/teleport/src/Roles/Roles.story.tsx index ecffcfa4144d9..e524da3e6d0d5 100644 --- a/web/packages/teleport/src/Roles/Roles.story.tsx +++ b/web/packages/teleport/src/Roles/Roles.story.tsx @@ -18,39 +18,53 @@ import { useEffect, useRef } from 'react'; +import { TeleportProviderBasic } from 'teleport/mocks/providers'; + import { Roles } from './Roles'; export default { title: 'Teleport/Roles', }; +export function Loaded() { + return ( + + + + ); +} + +export function Empty() { + return ( + + ({ items: [], startKey: '' })} />{' '} + + ); +} + export function Processing() { const promiseRef = useRef(Promise.withResolvers()); useEffect(() => { const promise = promiseRef.current; return () => promise.resolve(undefined); }, []); - return promiseRef.current.promise} />; -} - -export function Loaded() { - return ; -} - -export function Empty() { return ( - ({ items: [], startKey: '' })} /> + + promiseRef.current.promise} /> + ); } export function Failed() { return ( - { - throw new Error('some error message'); - }} - /> + + { + throw new Error('some error message'); + }} + /> + ); } diff --git a/web/packages/teleport/src/SamlApplications/useSamlAppActions.tsx b/web/packages/teleport/src/SamlApplications/useSamlAppActions.tsx index 1ea5977eb53f5..374c658ab38a4 100644 --- a/web/packages/teleport/src/SamlApplications/useSamlAppActions.tsx +++ b/web/packages/teleport/src/SamlApplications/useSamlAppActions.tsx @@ -20,7 +20,7 @@ import React, { createContext, useContext } from 'react'; import { Attempt } from 'shared/hooks/useAsync'; -import type { ResourceSpec } from 'teleport/Discover/SelectResource/types'; +import { SelectResourceSpec } from 'teleport/Discover/SelectResource/resources'; import { SamlMeta } from 'teleport/Discover/useDiscover'; import type { SamlAppToDelete } from 'teleport/services/samlidp/types'; import type { Access } from 'teleport/services/user'; @@ -40,11 +40,11 @@ export interface SamlAppAction { /** * startEdit triggers Saml app edit flow. */ - startEdit: (resourceSpec: ResourceSpec) => void; + startEdit: (resourceSpec: SelectResourceSpec) => void; /** * startDelete triggers Saml app delete flow. */ - startDelete: (resourceSpec: ResourceSpec) => void; + startDelete: (resourceSpec: SelectResourceSpec) => void; }; /** * currentAction specifies edit or delete mode. @@ -69,7 +69,7 @@ export interface SamlAppAction { /** * resourceSpec holds current Saml app resource spec. */ - resourceSpec?: ResourceSpec; + resourceSpec?: SelectResourceSpec; /** * userSamlIdPPerm holds user's RBAC permissions to * saml_idp_service_provider resource. diff --git a/web/packages/teleport/src/UnifiedResources/ResourceActionButton.tsx b/web/packages/teleport/src/UnifiedResources/ResourceActionButton.tsx index ec85d2c73c8c2..a1917e0c27437 100644 --- a/web/packages/teleport/src/UnifiedResources/ResourceActionButton.tsx +++ b/web/packages/teleport/src/UnifiedResources/ResourceActionButton.tsx @@ -31,7 +31,7 @@ import { AwsRole } from 'shared/services/apps'; import { TcpAppConnectDialog } from 'teleport/Apps/TcpAppConnectDialog'; import cfg from 'teleport/config'; import DbConnectDialog from 'teleport/Databases/ConnectDialog'; -import type { ResourceSpec } from 'teleport/Discover/SelectResource/types'; +import { SelectResourceSpec } from 'teleport/Discover/SelectResource/resources'; import { ResourceKind } from 'teleport/Discover/Shared'; import { ConnectDialog as GitServerConnectDialog } from 'teleport/GitServers'; import KubeConnectDialog from 'teleport/Kubes/ConnectDialog'; @@ -43,7 +43,9 @@ import { Database } from 'teleport/services/databases'; import { Desktop } from 'teleport/services/desktops'; import { Kube } from 'teleport/services/kube'; import { Node, sortNodeLogins } from 'teleport/services/nodes'; +import { SamlServiceProviderPreset } from 'teleport/services/samlidp/types'; import { DiscoverEventResource } from 'teleport/services/userEvent'; +import { DiscoverGuideId } from 'teleport/services/userPreferences/discoverPreference'; import useStickyClusterId from 'teleport/useStickyClusterId'; import useTeleport from 'teleport/useTeleport'; @@ -227,7 +229,19 @@ const AppLaunch = ({ app }: AppLaunchProps) => { } if (samlApp) { if (actions.showActions) { - const currentSamlAppSpec: ResourceSpec = { + let guideId: DiscoverGuideId; + switch (samlAppPreset) { + case SamlServiceProviderPreset.Grafana: + guideId = DiscoverGuideId.ApplicationSamlGrafana; + break; + case SamlServiceProviderPreset.GcpWorkforce: + guideId = DiscoverGuideId.ApplicationSamlWorkforceIdentityFederation; + break; + default: + guideId = DiscoverGuideId.ApplicationSamlGeneric; + } + const currentSamlAppSpec: SelectResourceSpec = { + id: guideId, name: name, event: DiscoverEventResource.SamlApplication, kind: ResourceKind.SamlApplication, diff --git a/web/packages/teleport/src/Users/Users.story.tsx b/web/packages/teleport/src/Users/Users.story.tsx index 9a6a5a4e79c9e..3dcbca0e3909c 100644 --- a/web/packages/teleport/src/Users/Users.story.tsx +++ b/web/packages/teleport/src/Users/Users.story.tsx @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import { MemoryRouter } from 'react-router'; +import { TeleportProviderBasic } from 'teleport/mocks/providers'; import { Users } from './Users'; @@ -24,33 +24,33 @@ export default { title: 'Teleport/Users', }; -export const Processing = () => { - const attempt = { - isProcessing: true, - isFailed: false, - isSuccess: false, - message: '', - }; - return ( - - - - ); -}; - export const Loaded = () => { return ( - + - + ); }; export const UsersNotEqualMauNotice = () => { return ( - + - + + ); +}; + +export const Processing = () => { + const attempt = { + isProcessing: true, + isFailed: false, + isSuccess: false, + message: '', + }; + return ( + + + ); }; @@ -62,9 +62,9 @@ export const Failed = () => { message: 'some error message', }; return ( - + - + ); }; diff --git a/web/packages/teleport/src/components/Wizard/Navigation/Bullet.tsx b/web/packages/teleport/src/components/Wizard/Navigation/Bullet.tsx index 4a376731aae68..1430af77e82ad 100644 --- a/web/packages/teleport/src/components/Wizard/Navigation/Bullet.tsx +++ b/web/packages/teleport/src/components/Wizard/Navigation/Bullet.tsx @@ -49,7 +49,7 @@ export const BulletContainer = styled.span` height: 14px; width: 14px; border: 1px solid ${p => p.theme.colors.text.disabled}; - font-size: ${p => p.theme.fontSizes[1]}px; + font-size: ${p => p.theme.fontSizes[0]}px; border-radius: 50%; margin-right: ${p => p.theme.space[2]}px; display: flex; diff --git a/web/packages/teleport/src/components/Wizard/Navigation/Shared.tsx b/web/packages/teleport/src/components/Wizard/Navigation/Shared.tsx index a3584529e2170..c79616f4c9b86 100644 --- a/web/packages/teleport/src/components/Wizard/Navigation/Shared.tsx +++ b/web/packages/teleport/src/components/Wizard/Navigation/Shared.tsx @@ -21,11 +21,11 @@ import styled from 'styled-components'; export const StepTitle = styled.div` display: flex; align-items: center; + font-size: ${p => p.theme.fontSizes[1]}px; `; export const StepsContainer = styled.div<{ active?: boolean }>` display: flex; - flex-direction: column; color: ${p => (p.active ? 'inherit' : p.theme.colors.text.slightlyMuted)}; margin-right: ${p => p.theme.space[5]}px; position: relative; diff --git a/web/packages/teleport/src/mocks/providers.tsx b/web/packages/teleport/src/mocks/providers.tsx new file mode 100644 index 0000000000000..4619a0d544f31 --- /dev/null +++ b/web/packages/teleport/src/mocks/providers.tsx @@ -0,0 +1,49 @@ +/** + * Teleport + * Copyright (C) 2025 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { LocationDescriptor } from 'history'; +import { PropsWithChildren } from 'react'; +import { MemoryRouter } from 'react-router'; + +import { getOSSFeatures } from 'teleport/features'; +import { FeaturesContextProvider } from 'teleport/FeaturesContext'; +import { ContextProvider } from 'teleport/index'; +import { InfoGuidePanelProvider } from 'teleport/Main/InfoGuideContext'; +import { createTeleportContext } from 'teleport/mocks/contexts'; +import TeleportContext from 'teleport/teleportContext'; + +export const TeleportProviderBasic: React.FC< + PropsWithChildren<{ + initialEntries?: LocationDescriptor[]; + teleportCtx?: TeleportContext; + }> +> = ({ children, initialEntries, teleportCtx }) => { + const ctx = teleportCtx || createTeleportContext(); + + return ( + + + + + {children} + + + + + ); +};