diff --git a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/__tests__/index.spec.tsx b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/__tests__/index.spec.tsx index ab06a26ec..9e6a78e45 100644 --- a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/__tests__/index.spec.tsx +++ b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/__tests__/index.spec.tsx @@ -13,6 +13,7 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ import { FACTORY_LINK_ATTR } from '@eclipse-che/common'; +import { AlertVariant } from '@patternfly/react-core'; import { cleanup, screen, waitFor } from '@testing-library/react'; import userEvent, { UserEvent } from '@testing-library/user-event'; import { createMemoryHistory, MemoryHistory } from 'history'; @@ -709,6 +710,7 @@ describe('Creating steps, fetching a devfile', () => { [FACTORY_URL_ATTR]: factoryUrl, }); + mockIsOAuthResponse.mockReturnValue(false); mockRequestFactoryResolver.mockRejectedValue('Could not reach devfile'); spyWindowLocation = createWindowLocationSpy(host, protocol); @@ -751,6 +753,46 @@ describe('Creating steps, fetching a devfile', () => { expect(mockOpenOAuthPage).not.toHaveBeenCalled(); expect(mockOnError).not.toHaveBeenCalled(); }); + + it('should show warning on SSH url', async () => { + const expectAlertItem = expect.objectContaining({ + title: 'Warning', + variant: AlertVariant.warning, + children: ( + + ), + actionCallbacks: [ + expect.objectContaining({ + title: 'Continue with default devfile', + callback: expect.any(Function), + }), + expect.objectContaining({ + title: 'Reload', + callback: expect.any(Function), + }), + expect.objectContaining({ + title: 'Open Documentation page', + callback: expect.any(Function), + }), + ], + }); + searchParams = new URLSearchParams({ + [FACTORY_URL_ATTR]: 'git@github.com:user/repository.git', + }); + const emptyStore = new FakeStoreBuilder().build(); + renderComponent(emptyStore, searchParams, history); + + await jest.advanceTimersByTimeAsync(MIN_STEP_DURATION_MS); + + await waitFor(() => expect(mockOnNextStep).not.toHaveBeenCalled); + + expect(mockOpenOAuthPage).not.toHaveBeenCalled(); + expect(mockOnError).toHaveBeenCalledWith(expectAlertItem); + }); }); }); diff --git a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/index.tsx b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/index.tsx index bab7eff55..003548951 100644 --- a/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/index.tsx +++ b/packages/dashboard-frontend/src/components/WorkspaceProgress/CreatingSteps/Fetch/Devfile/index.tsx @@ -35,6 +35,7 @@ import { AlertItem } from '@/services/helpers/types'; import { isOAuthResponse, OAuthService } from '@/services/oauth'; import SessionStorageService, { SessionStorageKey } from '@/services/session-storage'; import { AppState } from '@/store'; +import { selectBranding } from '@/store/Branding/selectors'; import { factoryResolverActionCreators, selectFactoryResolver } from '@/store/FactoryResolver'; import { selectAllWorkspaces } from '@/store/Workspaces/selectors'; @@ -52,6 +53,13 @@ export class UnsupportedGitProviderError extends Error { } } +export class SSHPrivateRepositoryUrlError extends Error { + constructor(message: string) { + super(message); + this.name = 'UnsupportedGitProviderError'; + } +} + const RELOADS_LIMIT = 2; type ReloadsInfo = { [url: string]: number; @@ -179,6 +187,10 @@ class CreatingStepFetchDevfile extends ProgressStep { this.clearStepError(); } + protected handleOpenDocumentationPage(): void { + window.open(this.props.branding.docs.startWorkspaceFromGit, '_blank'); + } + protected handleTimeout(): void { const timeoutError = new Error( `Devfile hasn't been resolved in the last ${TIMEOUT_TO_RESOLVE_SEC} seconds.`, @@ -220,7 +232,11 @@ class CreatingStepFetchDevfile extends ProgressStep { errorMessage === 'Failed to fetch devfile' || errorMessage.startsWith('Could not reach devfile') ) { - throw new UnsupportedGitProviderError(errorMessage); + if (sourceUrl.startsWith('git@')) { + throw new SSHPrivateRepositoryUrlError(errorMessage); + } else { + throw new UnsupportedGitProviderError(errorMessage); + } } throw e; } @@ -365,6 +381,34 @@ class CreatingStepFetchDevfile extends ProgressStep { ], }; } + if (error instanceof SSHPrivateRepositoryUrlError) { + return { + key, + title: 'Warning', + variant: AlertVariant.warning, + children: ( + + ), + actionCallbacks: [ + { + title: 'Continue with default devfile', + callback: () => this.handleDefaultDevfile(key), + }, + { + title: 'Reload', + callback: () => this.handleRestart(key), + }, + { + title: 'Open Documentation page', + callback: () => this.handleOpenDocumentationPage(), + }, + ], + }; + } return { key, title: 'Failed to create the workspace', @@ -417,6 +461,7 @@ class CreatingStepFetchDevfile extends ProgressStep { const mapStateToProps = (state: AppState) => ({ allWorkspaces: selectAllWorkspaces(state), factoryResolver: selectFactoryResolver(state), + branding: selectBranding(state), }); const connector = connect(mapStateToProps, factoryResolverActionCreators, null, { diff --git a/packages/dashboard-frontend/src/services/bootstrap/branding.constant.ts b/packages/dashboard-frontend/src/services/bootstrap/branding.constant.ts index 7f41b4157..15a492982 100644 --- a/packages/dashboard-frontend/src/services/bootstrap/branding.constant.ts +++ b/packages/dashboard-frontend/src/services/bootstrap/branding.constant.ts @@ -33,6 +33,7 @@ export type BrandingDocs = { faq?: string; storageTypes: string; webSocketTroubleshooting: string; + startWorkspaceFromGit: string; }; export type BrandingConfiguration = { @@ -83,6 +84,8 @@ export const BRANDING_DEFAULT: BrandingData = { 'https://www.eclipse.org/che/docs/stable/end-user-guide/url-parameter-for-the-workspace-storage/', webSocketTroubleshooting: 'https://www.eclipse.org/che/docs/stable/end-user-guide/troubleshooting-network-problems/', + startWorkspaceFromGit: + 'https://eclipse.dev/che/docs/stable/end-user-guide/starting-a-workspace-from-a-git-repository-url/', }, configuration: {}, };