Skip to content

Commit

Permalink
Merge branch 'main' into ft/config-overview
Browse files Browse the repository at this point in the history
  • Loading branch information
filiptronicek authored Nov 6, 2023
2 parents 931fa09 + 4c35db7 commit cd927ad
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 19 deletions.
55 changes: 52 additions & 3 deletions components/dashboard/src/components/RepositoryFinder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { ReactComponent as RepositoryIcon } from "../icons/RepositoryWithColor.s
import { SuggestedRepository } from "@gitpod/gitpod-protocol";
import { MiddleDot } from "./typography/MiddleDot";
import { useUnifiedRepositorySearch } from "../data/git-providers/unified-repositories-search-query";
import { useAuthProviders } from "../data/auth-providers/auth-provider-query";
import { ReactComponent as Exclamation2 } from "../images/exclamation2.svg";

interface RepositoryFinderProps {
selectedContextURL?: string;
Expand All @@ -30,7 +32,14 @@ export default function RepositoryFinder({
onChange,
}: RepositoryFinderProps) {
const [searchString, setSearchString] = useState("");
const { data: repos, isLoading, isSearching } = useUnifiedRepositorySearch({ searchString, excludeProjects });
const {
data: repos,
isLoading,
isSearching,
hasMore,
} = useUnifiedRepositorySearch({ searchString, excludeProjects });

const authProviders = useAuthProviders();

const handleSelectionChange = useCallback(
(selectedID: string) => {
Expand Down Expand Up @@ -87,15 +96,55 @@ export default function RepositoryFinder({
// searchString ignore here as list is already pre-filtered against it
// w/ mirrored state via useUnifiedRepositorySearch
(searchString: string) => {
return repos.map((repo) => {
const result = repos.map((repo) => {
return {
id: repo.projectId || repo.url,
element: <SuggestedRepositoryOption repo={repo} />,
isSelectable: true,
} as ComboboxElement;
});
if (hasMore) {
// add an element that tells the user to refince the search
result.push({
id: "more",
element: (
<div className="text-sm text-gray-400 dark:text-gray-500">
Repo missing? Try refining your search.
</div>
),
isSelectable: false,
} as ComboboxElement);
}
if (searchString.length >= 3 && authProviders.data?.some((p) => p.authProviderType === "BitbucketServer")) {
// add an element that tells the user that the Bitbucket Server does only support prefix search
result.push({
id: "bitbucket-server",
element: (
<div className="text-sm text-gray-400 dark:text-gray-500">
<div className="flex items-center">
<Exclamation2 className="w-4 h-4"></Exclamation2>
<span className="ml-2">Bitbucket Server only supports searching by prefix.</span>
</div>
</div>
),
isSelectable: false,
} as ComboboxElement);
}
if (searchString.length < 3) {
// add an element that tells the user to type more
result.push({
id: "not-searched",
element: (
<div className="text-sm text-gray-400 dark:text-gray-500">
Please type at least 3 characters to search.
</div>
),
isSelectable: false,
} as ComboboxElement);
}
return result;
},
[repos],
[repos, hasMore, authProviders.data],
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,19 @@ import { useCurrentOrg } from "../organizations/orgs-query";
import { useDebounce } from "../../hooks/use-debounce";
import { useFeatureFlag } from "../featureflag-query";

export const useSearchRepositories = ({ searchString }: { searchString: string }) => {
export const useSearchRepositories = ({ searchString, limit }: { searchString: string; limit: number }) => {
// This disables the search behavior when flag is disabled
const repositoryFinderSearchEnabled = useFeatureFlag("repositoryFinderSearch");
const { data: org } = useCurrentOrg();
const debouncedSearchString = useDebounce(searchString);

return useQuery(
["search-repositories", { organizationId: org?.id || "", searchString: debouncedSearchString }],
["search-repositories", { organizationId: org?.id || "", searchString: debouncedSearchString, limit }],
async () => {
return await getGitpodService().server.searchRepositories({
searchString,
organizationId: org?.id ?? "",
limit,
});
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@ type UnifiedRepositorySearchArgs = {
// Combines the suggested repositories and the search repositories query into one hook
export const useUnifiedRepositorySearch = ({ searchString, excludeProjects = false }: UnifiedRepositorySearchArgs) => {
const suggestedQuery = useSuggestedRepositories();
const searchQuery = useSearchRepositories({ searchString });
const searchLimit = 30;
const searchQuery = useSearchRepositories({ searchString, limit: searchLimit });

const filteredRepos = useMemo(() => {
const flattenedRepos = [suggestedQuery.data || [], searchQuery.data || []].flat();

return deduplicateAndFilterRepositories(searchString, excludeProjects, flattenedRepos);
}, [excludeProjects, searchQuery.data, searchString, suggestedQuery.data]);

return {
data: filteredRepos,
hasMore: searchQuery.data?.length === searchLimit,
isLoading: suggestedQuery.isLoading,
isSearching: searchQuery.isFetching,
isError: suggestedQuery.isError || searchQuery.isError,
Expand Down
4 changes: 2 additions & 2 deletions components/dashboard/src/workspaces/CreateWorkspacePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ export function CreateWorkspacePage() {
if (needsGitAuthorization) {
return (
<div className="flex flex-col mt-32 mx-auto ">
<div className="flex flex-col max-h-screen max-w-lg mx-auto items-center w-full">
<div className="flex flex-col max-h-screen max-w-xl mx-auto items-center w-full">
<Heading1>New Workspace</Heading1>
<div className="text-gray-500 text-center text-base">
Start a new workspace with the following options.
Expand All @@ -367,7 +367,7 @@ export function CreateWorkspacePage() {

return (
<div className="flex flex-col mt-32 mx-auto ">
<div className="flex flex-col max-h-screen max-w-lg mx-auto items-center w-full">
<div className="flex flex-col max-h-screen max-w-xl mx-auto items-center w-full">
<Heading1>New Workspace</Heading1>
<div className="text-gray-500 text-center text-base">
Create a new workspace in the{" "}
Expand Down
1 change: 1 addition & 0 deletions components/gitpod-protocol/src/gitpod-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ export interface GetProviderRepositoriesParams {
export interface SearchRepositoriesParams {
organizationId: string;
searchString: string;
limit?: number; // defaults to 30
}
export interface ProviderRepository {
name: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,9 @@ export class BitbucketServerRepositoryProvider implements RepositoryProvider {
return commits.map((c) => c.id);
}

public async searchRepos(user: User, searchString: string): Promise<RepositoryInfo[]> {
// Only load 1 page of 10 results for our searchString
const results = await this.api.getRepos(user, { maxPages: 1, limit: 30, searchString });
public async searchRepos(user: User, searchString: string, limit: number): Promise<RepositoryInfo[]> {
// Only load 1 page of limit results for our searchString
const results = await this.api.getRepos(user, { maxPages: 1, limit, searchString });

const repos: RepositoryInfo[] = [];
results.forEach((r) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,10 @@ export class BitbucketRepositoryProvider implements RepositoryProvider {
// 1. Get all workspaces for the user
// 2. Fan out and search each workspace for the repos
//
public async searchRepos(user: User, searchString: string): Promise<RepositoryInfo[]> {
public async searchRepos(user: User, searchString: string, limit: number): Promise<RepositoryInfo[]> {
const api = await this.apiFactory.create(user);

const workspaces = await api.workspaces.getWorkspaces({ pagelen: 25 });
const workspaces = await api.workspaces.getWorkspaces({ pagelen: limit });

const workspaceSlugs: string[] = (
workspaces.data.values?.map((w) => {
Expand Down
4 changes: 2 additions & 2 deletions components/server/src/github/github-repository-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ export class GithubRepositoryProvider implements RepositoryProvider {
return repos;
}

public async searchRepos(user: User, searchString: string): Promise<RepositoryInfo[]> {
public async searchRepos(user: User, searchString: string, limit: number): Promise<RepositoryInfo[]> {
// graphql api only returns public orgs, so we need to use the rest api to get both public & private orgs
const orgs = await this.github.run(user, async (api) => {
return api.orgs.listMembershipsForAuthenticatedUser({
Expand All @@ -245,7 +245,7 @@ export class GithubRepositoryProvider implements RepositoryProvider {
const query = JSON.stringify(`${searchString} in:name user:@me ${orgFilters}`);
const repoSearchQuery = `
query SearchRepos {
search (type: REPOSITORY, first: 10, query: ${query}){
search (type: REPOSITORY, first: ${limit}, query: ${query}){
edges {
node {
... on Repository {
Expand Down
3 changes: 2 additions & 1 deletion components/server/src/gitlab/gitlab-repository-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,12 @@ export class GitlabRepositoryProvider implements RepositoryProvider {
return result.slice(1).map((c: GitLab.Commit) => c.id);
}

public async searchRepos(user: User, searchString: string): Promise<RepositoryInfo[]> {
public async searchRepos(user: User, searchString: string, limit: number): Promise<RepositoryInfo[]> {
const result = await this.gitlab.run<GitLab.Project[]>(user, async (gitlab) => {
return gitlab.Projects.all({
membership: true,
search: searchString,
perPage: limit,
simple: true,
});
});
Expand Down
2 changes: 1 addition & 1 deletion components/server/src/repohost/repository-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ export interface RepositoryProvider {
getUserRepos(user: User): Promise<RepositoryInfo[]>;
hasReadAccess(user: User, owner: string, repo: string): Promise<boolean>;
getCommitHistory(user: User, owner: string, repo: string, ref: string, maxDepth: number): Promise<string[]>;
searchRepos(user: User, searchString: string): Promise<RepositoryInfo[]>;
searchRepos(user: User, searchString: string, limit: number): Promise<RepositoryInfo[]>;
}
6 changes: 4 additions & 2 deletions components/server/src/workspace/gitpod-server-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1694,6 +1694,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
const user = await this.checkAndBlockUser("searchRepositories");

const logCtx: LogContext = { userId: user.id };
const limit: number = params.limit || 30;

// Search repos across scm providers for this user
// Will search personal, and org repos
Expand All @@ -1708,7 +1709,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
log.error(logCtx, "Unsupported repository host: " + p.host);
return [];
}
const repos = await services.repositoryProvider.searchRepos(user, params.searchString);
const repos = await services.repositoryProvider.searchRepos(user, params.searchString, limit);

return repos.map((r) =>
suggestionFromUserRepo({
Expand All @@ -1726,7 +1727,8 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {

const sortedRepos = sortSuggestedRepositories(providerRepos.flat());

return sortedRepos.map(
//return only the first 'limit' results
return sortedRepos.slice(0, limit).map(
(repo): SuggestedRepository => ({
url: repo.url,
repositoryName: repo.repositoryName,
Expand Down

0 comments on commit cd927ad

Please sign in to comment.