Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion e
Submodule e updated from b3710b to e1aaa6
30 changes: 21 additions & 9 deletions web/packages/teleterm/src/services/tshd/createClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,24 @@ export default function createClient(
async getKubes({
clusterUri,
search,
sort = { fieldName: 'name', dir: 'ASC' },
sort,
query,
searchAsRoles,
startKey,
limit,
}: types.ServerSideParams) {
}: types.GetResourcesParams) {
const req = new api.GetKubesRequest()
.setClusterUri(clusterUri)
.setSearchAsRoles(searchAsRoles)
.setStartKey(startKey)
.setSortBy(`${sort.fieldName}:${sort.dir.toLowerCase()}`)
.setSearch(search)
.setQuery(query)
.setLimit(limit);

if (sort) {
req.setSortBy(`${sort.fieldName}:${sort.dir.toLowerCase()}`);
}

return new Promise<types.GetKubesResponse>((resolve, reject) => {
tshd.getKubes(req, (err, response) => {
if (err) {
Expand Down Expand Up @@ -128,20 +132,24 @@ export default function createClient(
async getDatabases({
clusterUri,
search,
sort = { fieldName: 'name', dir: 'ASC' },
sort,
query,
searchAsRoles,
startKey,
limit,
}: types.ServerSideParams) {
}: types.GetResourcesParams) {
const req = new api.GetDatabasesRequest()
.setClusterUri(clusterUri)
.setSearchAsRoles(searchAsRoles)
.setStartKey(startKey)
.setSortBy(`${sort.fieldName}:${sort.dir.toLowerCase()}`)
.setSearch(search)
.setQuery(query)
.setLimit(limit);

if (sort) {
req.setSortBy(`${sort.fieldName}:${sort.dir.toLowerCase()}`);
}

return new Promise<types.GetDatabasesResponse>((resolve, reject) => {
tshd.getDatabases(req, (err, response) => {
if (err) {
Expand Down Expand Up @@ -198,19 +206,23 @@ export default function createClient(
clusterUri,
search,
query,
sort = { fieldName: 'hostname', dir: 'ASC' },
sort,
searchAsRoles,
startKey,
limit,
}: types.ServerSideParams) {
}: types.GetResourcesParams) {
const req = new api.GetServersRequest()
.setClusterUri(clusterUri)
.setSearchAsRoles(searchAsRoles)
.setStartKey(startKey)
.setSortBy(`${sort.fieldName}:${sort.dir.toLowerCase()}`)
.setSearch(search)
.setQuery(query)
.setLimit(limit);

if (sort) {
req.setSortBy(`${sort.fieldName}:${sort.dir.toLowerCase()}`);
}

return new Promise<types.GetServersResponse>((resolve, reject) => {
tshd.getServers(req, (err, response) => {
if (err) {
Expand Down
8 changes: 4 additions & 4 deletions web/packages/teleterm/src/services/tshd/fixtures/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
LoginPasswordlessParams,
LoginSsoParams,
ReviewAccessRequestParams,
ServerSideParams,
GetResourcesParams,
TshAbortController,
TshAbortSignal,
TshClient,
Expand All @@ -39,13 +39,13 @@ import {
export class MockTshClient implements TshClient {
listRootClusters: () => Promise<Cluster[]>;
listLeafClusters: (clusterUri: string) => Promise<Cluster[]>;
getKubes: (params: ServerSideParams) => Promise<GetKubesResponse>;
getDatabases: (params: ServerSideParams) => Promise<GetDatabasesResponse>;
getKubes: (params: GetResourcesParams) => Promise<GetKubesResponse>;
getDatabases: (params: GetResourcesParams) => Promise<GetDatabasesResponse>;
listDatabaseUsers: (dbUri: string) => Promise<string[]>;
getRequestableRoles: (
params: GetRequestableRolesParams
) => Promise<GetRequestableRolesResponse>;
getServers: (params: ServerSideParams) => Promise<GetServersResponse>;
getServers: (params: GetResourcesParams) => Promise<GetServersResponse>;
assumeRole: (
clusterUri: string,
requestIds: string[],
Expand Down
19 changes: 13 additions & 6 deletions web/packages/teleterm/src/services/tshd/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,8 @@ export type LoginPasswordlessRequest =
export type TshClient = {
listRootClusters: () => Promise<Cluster[]>;
listLeafClusters: (clusterUri: uri.RootClusterUri) => Promise<Cluster[]>;
getKubes: (params: ServerSideParams) => Promise<GetKubesResponse>;
getDatabases: (params: ServerSideParams) => Promise<GetDatabasesResponse>;
getKubes: (params: GetResourcesParams) => Promise<GetKubesResponse>;
getDatabases: (params: GetResourcesParams) => Promise<GetDatabasesResponse>;
listDatabaseUsers: (dbUri: uri.DatabaseUri) => Promise<string[]>;
assumeRole: (
clusterUri: uri.RootClusterUri,
Expand All @@ -155,7 +155,7 @@ export type TshClient = {
getRequestableRoles: (
params: GetRequestableRolesParams
) => Promise<GetRequestableRolesResponse>;
getServers: (params: ServerSideParams) => Promise<GetServersResponse>;
getServers: (params: GetResourcesParams) => Promise<GetServersResponse>;
getAccessRequests: (
clusterUri: uri.RootClusterUri
) => Promise<AccessRequest[]>;
Expand Down Expand Up @@ -248,18 +248,25 @@ export type CreateGatewayParams = {
subresource_name?: string;
};

export type ServerSideParams = {
export type GetResourcesParams = {
clusterUri: uri.ClusterUri;
// sort is a required field because it has direct implications on performance of ListResources.
sort: SortType | null;
// limit cannot be omitted and must be greater than zero, otherwise ListResources is going to
// return an error.
limit: number;
// search is used for regular search.
search?: string;
searchAsRoles?: string;
sort?: SortType;
startKey?: string;
limit?: number;
// query is used for advanced search.
query?: string;
};

// Compatibility type to make sure teleport.e doesn't break.
// TODO(ravicious): Remove after teleterm.e is updated to use GetResourcesParams.
export type ServerSideParams = GetResourcesParams;

export type ReviewAccessRequestParams = {
state: RequestState;
reason: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ function getMenuLoginOptions(
async function getDatabaseUsers(appContext: IAppContext, dbUri: DatabaseUri) {
try {
const dbUsers = await retryWithRelogin(appContext, dbUri, () =>
appContext.clustersService.getDbUsers(dbUri)
appContext.resourcesService.getDbUsers(dbUri)
);
return dbUsers.map(user => ({ login: user, url: '' }));
} catch (e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { useAppContext } from 'teleterm/ui/appContextProvider';
import {
Database,
GatewayProtocol,
ServerSideParams,
GetResourcesParams,
} from 'teleterm/services/tshd/types';
import { routing } from 'teleterm/ui/uri';
import { makeDatabase } from 'teleterm/ui/services/clusters';
Expand All @@ -31,7 +31,7 @@ export function useDatabases() {
const { fetchAttempt, ...serverSideResources } =
useServerSideResources<Database>(
{ fieldName: 'name', dir: 'ASC' }, // default sort
(params: ServerSideParams) =>
(params: GetResourcesParams) =>
appContext.resourcesService.fetchDatabases(params)
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import { Kube, ServerSideParams } from 'teleterm/services/tshd/types';
import { Kube, GetResourcesParams } from 'teleterm/services/tshd/types';
import { useAppContext } from 'teleterm/ui/appContextProvider';
import { useClusterContext } from 'teleterm/ui/DocumentCluster/clusterContext';

Expand All @@ -25,7 +25,8 @@ export function useKubes() {
const ctx = useClusterContext();
const { fetchAttempt, ...serversideResources } = useServerSideResources<Kube>(
{ fieldName: 'name', dir: 'ASC' }, // default sort
(params: ServerSideParams) => appContext.resourcesService.fetchKubes(params)
(params: GetResourcesParams) =>
appContext.resourcesService.fetchKubes(params)
);

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { Server, ServerSideParams } from 'teleterm/services/tshd/types';
import { Server, GetResourcesParams } from 'teleterm/services/tshd/types';
import { useAppContext } from 'teleterm/ui/appContextProvider';
import { makeServer } from 'teleterm/ui/services/clusters';

Expand All @@ -27,7 +27,7 @@ export function useServers() {
const { fetchAttempt, ...serversideResources } =
useServerSideResources<Server>(
{ fieldName: 'hostname', dir: 'ASC' }, // default sort
(params: ServerSideParams) =>
(params: GetResourcesParams) =>
appContext.resourcesService.fetchServers(params)
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,19 @@
import { useState, useEffect, useMemo } from 'react';
import { SortType } from 'design/DataTable/types';
import { useAsync } from 'shared/hooks/useAsync';
import { AgentFilter, AgentLabel } from 'teleport/services/agents';
import {
AgentFilter as WeakAgentFilter,
AgentLabel,
} from 'teleport/services/agents';

import { ServerSideParams } from 'teleterm/services/tshd/types';
import { GetResourcesParams } from 'teleterm/services/tshd/types';
import { useAppContext } from 'teleterm/ui/appContextProvider';
import { retryWithRelogin } from 'teleterm/ui/utils';

import { useClusterContext } from '../clusterContext';

type AgentFilter = WeakAgentFilter & { sort: SortType };

function addAgentLabelToQuery(filter: AgentFilter, label: AgentLabel) {
const queryParts = [];

Expand All @@ -49,7 +54,7 @@ const limit = 15;

export function useServerSideResources<Agent>(
defaultSort: SortType,
fetchFunction: (params: ServerSideParams) => Promise<FetchResponse<Agent>>
fetchFunction: (params: GetResourcesParams) => Promise<FetchResponse<Agent>>
) {
const ctx = useAppContext();
const { clusterUri } = useClusterContext();
Expand Down
45 changes: 45 additions & 0 deletions web/packages/teleterm/src/ui/Search/useSearch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Copyright 2023 Gravitational, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { useCallback } from 'react';

import { useAppContext } from 'teleterm/ui/appContextProvider';

/**
* useSearch returns a function which searches for the given list of space-separated keywords across
* all root and leaf clusters that the user is currently logged in to.
*
* It does so by issuing a separate request for each resource type to each cluster. It fails if any
* of those requests fail.
*/
export function useSearch() {
const { clustersService, resourcesService } = useAppContext();
clustersService.useState();

return useCallback(
async (search: string) => {
const connectedClusters = clustersService
.getClusters()
.filter(c => c.connected);
const searchPromises = connectedClusters.map(cluster =>
resourcesService.searchResources(cluster.uri, search)
);

return (await Promise.all(searchPromises)).flat();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice

},
[clustersService, resourcesService]
);
}
21 changes: 10 additions & 11 deletions web/packages/teleterm/src/ui/services/clusters/clustersService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
CreateAccessRequestParams,
GetRequestableRolesParams,
ReviewAccessRequestParams,
ServerSideParams,
GetResourcesParams,
} from 'teleterm/services/tshd/types';
import { MainProcessClient } from 'teleterm/mainProcess/types';
import { UsageService } from 'teleterm/ui/services/usage';
Expand Down Expand Up @@ -196,6 +196,8 @@ export class ClustersService extends ImmutableStore<types.ClustersServiceState>

async getRequestableRoles(params: GetRequestableRolesParams) {
const cluster = this.state.clusters.get(params.rootClusterUri);
// TODO(ravicious): Remove check for cluster.connected. This check should be done earlier in the
// UI rather than be repeated in each ClustersService method.
if (!cluster.connected) {
return;
}
Expand All @@ -205,6 +207,7 @@ export class ClustersService extends ImmutableStore<types.ClustersServiceState>

getAssumedRequests(rootClusterUri: uri.RootClusterUri) {
const cluster = this.state.clusters.get(rootClusterUri);
// TODO(ravicious): Remove check for cluster.connected. See the comment in getRequestableRoles.
if (!cluster?.connected) {
return {};
}
Expand All @@ -218,6 +221,7 @@ export class ClustersService extends ImmutableStore<types.ClustersServiceState>

async getAccessRequests(rootClusterUri: uri.RootClusterUri) {
const cluster = this.state.clusters.get(rootClusterUri);
// TODO(ravicious): Remove check for cluster.connected. See the comment in getRequestableRoles.
if (!cluster.connected) {
return;
}
Expand All @@ -230,6 +234,7 @@ export class ClustersService extends ImmutableStore<types.ClustersServiceState>
requestId: string
) {
const cluster = this.state.clusters.get(rootClusterUri);
// TODO(ravicious): Remove check for cluster.connected. See the comment in getRequestableRoles.
if (!cluster.connected) {
return;
}
Expand All @@ -242,6 +247,7 @@ export class ClustersService extends ImmutableStore<types.ClustersServiceState>
dropIds: string[]
) {
const cluster = this.state.clusters.get(rootClusterUri);
// TODO(ravicious): Remove check for cluster.connected. See the comment in getRequestableRoles.
if (!cluster.connected) {
return;
}
Expand All @@ -255,6 +261,7 @@ export class ClustersService extends ImmutableStore<types.ClustersServiceState>
requestId: string
) {
const cluster = this.state.clusters.get(rootClusterUri);
// TODO(ravicious): Remove check for cluster.connected. See the comment in getRequestableRoles.
if (!cluster.connected) {
return;
}
Expand All @@ -267,6 +274,7 @@ export class ClustersService extends ImmutableStore<types.ClustersServiceState>
params: ReviewAccessRequestParams
) {
const cluster = this.state.clusters.get(rootClusterUri);
// TODO(ravicious): Remove check for cluster.connected. See the comment in getRequestableRoles.
if (!cluster.connected) {
return;
}
Expand All @@ -281,6 +289,7 @@ export class ClustersService extends ImmutableStore<types.ClustersServiceState>

async createAccessRequest(params: CreateAccessRequestParams) {
const cluster = this.state.clusters.get(params.rootClusterUri);
// TODO(ravicious): Remove check for cluster.connected. See the comment in getRequestableRoles.
if (!cluster.connected) {
return;
}
Expand Down Expand Up @@ -426,16 +435,6 @@ export class ClustersService extends ImmutableStore<types.ClustersServiceState>
return this.getClusters().filter(c => !c.leaf);
}

// TODO(ravicious): Use ResourcesService instead.
async fetchKubes(params: ServerSideParams) {
return await this.client.getKubes(params);
}

// TODO(ravicious): Move to ResourceService.
async getDbUsers(dbUri: uri.DatabaseUri): Promise<string[]> {
return await this.client.listDatabaseUsers(dbUri);
}

async removeClusterKubeConfigs(clusterUri: string): Promise<void> {
const {
params: { rootClusterId },
Expand Down
Loading