From 0324d86ec79c3997334a6824a8d1747839cb1346 Mon Sep 17 00:00:00 2001 From: Grzegorz Zdunek Date: Tue, 29 Mar 2022 13:57:53 +0200 Subject: [PATCH] Use `Notifications` error in `syncRootCluster()` and `removeGateway()` --- web/packages/teleterm/src/ui/App.tsx | 2 + web/packages/teleterm/src/ui/appContext.ts | 8 ++- .../services/clusters/clustersService.test.ts | 2 +- .../ui/services/clusters/clustersService.ts | 55 +++++++++++++------ .../quickInput/quickInputService.test.ts | 32 +++++------ 5 files changed, 64 insertions(+), 35 deletions(-) diff --git a/web/packages/teleterm/src/ui/App.tsx b/web/packages/teleterm/src/ui/App.tsx index 34e3b15fb0d..3d6fa5d33e7 100644 --- a/web/packages/teleterm/src/ui/App.tsx +++ b/web/packages/teleterm/src/ui/App.tsx @@ -9,6 +9,7 @@ import AppContext from './appContext'; import ThemeProvider from './ThemeProvider'; import { LayoutManager } from './LayoutManager'; import { AppInitializer } from 'teleterm/ui/AppInitializer'; +import { NotificationsHost } from 'teleterm/ui/components/Notifcations'; const App: React.FC<{ ctx: AppContext }> = ({ ctx }) => { const { appearance } = ctx.mainProcessClient.configService.get(); @@ -21,6 +22,7 @@ const App: React.FC<{ ctx: AppContext }> = ({ ctx }) => { + diff --git a/web/packages/teleterm/src/ui/appContext.ts b/web/packages/teleterm/src/ui/appContext.ts index 498c5adf155..e24811267a6 100644 --- a/web/packages/teleterm/src/ui/appContext.ts +++ b/web/packages/teleterm/src/ui/appContext.ts @@ -24,10 +24,12 @@ import { StatePersistenceService } from 'teleterm/ui/services/statePersistence'; import { KeyboardShortcutsService } from 'teleterm/ui/services/keyboardShortcuts'; import { CommandLauncher } from './commandLauncher'; import { WorkspacesService } from 'teleterm/ui/services/workspacesService/workspacesService'; +import { NotificationsService } from 'teleterm/ui/services/notifications'; export default class AppContext { clustersService: ClustersService; modalsService: ModalsService; + notificationsService: NotificationsService; terminalsService: TerminalsService; keyboardShortcutsService: KeyboardShortcutsService; quickInputService: QuickInputService; @@ -43,8 +45,12 @@ export default class AppContext { this.statePersistenceService = new StatePersistenceService( config.fileStorage ); - this.clustersService = new ClustersService(tshClient); this.modalsService = new ModalsService(); + this.notificationsService = new NotificationsService(); + this.clustersService = new ClustersService( + tshClient, + this.notificationsService + ); this.workspacesService = new WorkspacesService( this.clustersService, this.modalsService, diff --git a/web/packages/teleterm/src/ui/services/clusters/clustersService.test.ts b/web/packages/teleterm/src/ui/services/clusters/clustersService.test.ts index 2103c8e0f5a..e5eed846fb5 100644 --- a/web/packages/teleterm/src/ui/services/clusters/clustersService.test.ts +++ b/web/packages/teleterm/src/ui/services/clusters/clustersService.test.ts @@ -84,7 +84,7 @@ const appMock: tsh.Application = { }; function createService(client: Partial): ClustersService { - return new ClustersService(client as tsh.TshClient); + return new ClustersService(client as tsh.TshClient, undefined); } function getClientMocks(): Partial { diff --git a/web/packages/teleterm/src/ui/services/clusters/clustersService.ts b/web/packages/teleterm/src/ui/services/clusters/clustersService.ts index 14a30362aa2..a054e957bda 100644 --- a/web/packages/teleterm/src/ui/services/clusters/clustersService.ts +++ b/web/packages/teleterm/src/ui/services/clusters/clustersService.ts @@ -1,17 +1,18 @@ import { useStore } from 'shared/libs/stores'; import { - tsh, - SyncStatus, AuthSettings, - LoginParams, ClustersServiceState, CreateGatewayParams, + LoginParams, + SyncStatus, + tsh, } from './types'; import { ImmutableStore } from '../immutableStore'; import { routing } from 'teleterm/ui/uri'; import isMatch from 'design/utils/match'; import { makeLabelTag } from 'teleport/components/formatters'; import { Label } from 'teleport/types'; +import { NotificationsService } from 'teleterm/ui/services/notifications'; export function createClusterServiceState(): ClustersServiceState { return { @@ -31,7 +32,10 @@ export function createClusterServiceState(): ClustersServiceState { export class ClustersService extends ImmutableStore { state: ClustersServiceState = createClusterServiceState(); - constructor(public client: tsh.TshClient) { + constructor( + public client: tsh.TshClient, + private notificationsService: NotificationsService + ) { super(); } @@ -56,15 +60,25 @@ export class ClustersService extends ImmutableStore { } async syncRootCluster(clusterUri: string) { - await this.syncClusterInfo(clusterUri); + try { + await this.syncClusterInfo(clusterUri); - this.syncLeafClusters(clusterUri); - this.syncKubes(clusterUri); - this.syncApps(clusterUri); - this.syncDbs(clusterUri); - this.syncServers(clusterUri); - this.syncKubes(clusterUri); - this.syncGateways(); + this.syncLeafClusters(clusterUri); + this.syncKubes(clusterUri); + this.syncApps(clusterUri); + this.syncDbs(clusterUri); + this.syncServers(clusterUri); + this.syncKubes(clusterUri); + this.syncGateways(); + } catch (e) { + this.notificationsService.notifyError({ + title: `Could not synchronize cluster ${ + routing.parseClusterUri(clusterUri).params.rootClusterId + }`, + description: e.message, + }); + throw e; + } } async syncLeafCluster(clusterUri: string) { @@ -79,7 +93,6 @@ export class ClustersService extends ImmutableStore { async syncRootClusters() { const clusters = await this.client.listRootClusters(); - console.log('synced', clusters); this.setState(draft => { draft.clusters = new Map(clusters.map(c => [c.uri, c])); }); @@ -271,10 +284,18 @@ export class ClustersService extends ImmutableStore { } async removeGateway(gatewayUri: string) { - await this.client.removeGateway(gatewayUri); - this.setState(draft => { - draft.gateways.delete(gatewayUri); - }); + try { + await this.client.removeGateway(gatewayUri); + this.setState(draft => { + draft.gateways.delete(gatewayUri); + }); + } catch (error) { + this.notificationsService.notifyError({ + title: 'Could not close the database connection', + description: error.message, + }); + throw error; + } } findCluster(clusterUri: string) { diff --git a/web/packages/teleterm/src/ui/services/quickInput/quickInputService.test.ts b/web/packages/teleterm/src/ui/services/quickInput/quickInputService.test.ts index 7d6231a888a..6d83e8319b3 100644 --- a/web/packages/teleterm/src/ui/services/quickInput/quickInputService.test.ts +++ b/web/packages/teleterm/src/ui/services/quickInput/quickInputService.test.ts @@ -60,7 +60,7 @@ test('getAutocompleteResult returns correct result for a command suggestion with ); const quickInputService = new QuickInputService( new CommandLauncherMock(undefined), - new ClustersServiceMock(undefined), + new ClustersServiceMock(undefined, undefined), new WorkspacesServiceMock(undefined, undefined, undefined) ); @@ -80,7 +80,7 @@ test('getAutocompleteResult returns correct result for a command suggestion', () ); const quickInputService = new QuickInputService( new CommandLauncherMock(undefined), - new ClustersServiceMock(undefined), + new ClustersServiceMock(undefined, undefined), new WorkspacesServiceMock(undefined, undefined, undefined) ); @@ -117,7 +117,7 @@ test('getAutocompleteResult returns correct result for an SSH login suggestion', }); const quickInputService = new QuickInputService( new CommandLauncherMock(undefined), - new ClustersServiceMock(undefined), + new ClustersServiceMock(undefined, undefined), new WorkspacesServiceMock(undefined, undefined, undefined) ); @@ -158,7 +158,7 @@ test('getAutocompleteResult returns correct result for an SSH login suggestion w }); const quickInputService = new QuickInputService( new CommandLauncherMock(undefined), - new ClustersServiceMock(undefined), + new ClustersServiceMock(undefined, undefined), new WorkspacesServiceMock(undefined, undefined, undefined) ); @@ -209,7 +209,7 @@ test('getAutocompleteResult returns correct result for a database name suggestio }); const quickInputService = new QuickInputService( new CommandLauncherMock(undefined), - new ClustersServiceMock(undefined), + new ClustersServiceMock(undefined, undefined), new WorkspacesServiceMock(undefined, undefined, undefined) ); @@ -250,7 +250,7 @@ test("getAutocompleteResult doesn't return any suggestions if the only suggestio }); const quickInputService = new QuickInputService( new CommandLauncherMock(undefined), - new ClustersServiceMock(undefined), + new ClustersServiceMock(undefined, undefined), new WorkspacesServiceMock(undefined, undefined, undefined) ); @@ -279,7 +279,7 @@ test('getAutocompleteResult returns no match if any of the pickers returns parti }); const quickInputService = new QuickInputService( new CommandLauncherMock(undefined), - new ClustersServiceMock(undefined), + new ClustersServiceMock(undefined, undefined), new WorkspacesServiceMock(undefined, undefined, undefined) ); @@ -295,7 +295,7 @@ test("the SSH login autocomplete isn't shown if there's no space after `tsh ssh` ); const quickInputService = new QuickInputService( new CommandLauncherMock(undefined), - new ClustersServiceMock(undefined), + new ClustersServiceMock(undefined, undefined), new WorkspacesServiceMock(undefined, undefined, undefined) ); @@ -328,7 +328,7 @@ test("the SSH login autocomplete is shown only if there's at least one space aft }); const quickInputService = new QuickInputService( new CommandLauncherMock(undefined), - new ClustersServiceMock(undefined), + new ClustersServiceMock(undefined, undefined), new WorkspacesServiceMock(undefined, undefined, undefined) ); @@ -370,7 +370,7 @@ test('getAutocompleteResult returns correct result for an SSH host suggestion ri }); const quickInputService = new QuickInputService( new CommandLauncherMock(undefined), - new ClustersServiceMock(undefined), + new ClustersServiceMock(undefined, undefined), new WorkspacesServiceMock(undefined, undefined, undefined) ); @@ -415,7 +415,7 @@ test('getAutocompleteResult returns correct result for a partial match on an SSH })); const quickInputService = new QuickInputService( new CommandLauncherMock(undefined), - new ClustersServiceMock(undefined), + new ClustersServiceMock(undefined, undefined), new WorkspacesServiceMock(undefined, undefined, undefined) ); @@ -457,7 +457,7 @@ test("getAutocompleteResult returns the first argument as loginHost when there's }); const quickInputService = new QuickInputService( new CommandLauncherMock(undefined), - new ClustersServiceMock(undefined), + new ClustersServiceMock(undefined, undefined), new WorkspacesServiceMock(undefined, undefined, undefined) ); @@ -477,7 +477,7 @@ test("getAutocompleteResult returns the first argument as loginHost when there's test('picking a command suggestion in an empty input autocompletes the command', () => { const quickInputService = new QuickInputService( new CommandLauncherMock(undefined), - new ClustersServiceMock(undefined), + new ClustersServiceMock(undefined, undefined), new WorkspacesServiceMock(undefined, undefined, undefined) ); quickInputService.setState({ inputValue: '' }); @@ -503,7 +503,7 @@ test('picking a command suggestion in an empty input autocompletes the command', test('picking a command suggestion in an input with a single space preserves the space', () => { const quickInputService = new QuickInputService( new CommandLauncherMock(undefined), - new ClustersServiceMock(undefined), + new ClustersServiceMock(undefined, undefined), new WorkspacesServiceMock(undefined, undefined, undefined) ); quickInputService.setState({ inputValue: ' ' }); @@ -529,7 +529,7 @@ test('picking a command suggestion in an input with a single space preserves the test('picking an SSH login suggestion replaces target token in input value', () => { const quickInputService = new QuickInputService( new CommandLauncherMock(undefined), - new ClustersServiceMock(undefined), + new ClustersServiceMock(undefined, undefined), new WorkspacesServiceMock(undefined, undefined, undefined) ); quickInputService.setState({ inputValue: 'tsh ssh roo --foo' }); @@ -552,7 +552,7 @@ test('picking an SSH login suggestion replaces target token in input value', () test('pickSuggestion appends the appendToToken field to the token', () => { const quickInputService = new QuickInputService( new CommandLauncherMock(undefined), - new ClustersServiceMock(undefined), + new ClustersServiceMock(undefined, undefined), new WorkspacesServiceMock(undefined, undefined, undefined) ); quickInputService.setState({ inputValue: 'tsh ssh foo' });