diff --git a/components/dashboard/src/components/RepositoryFinder.tsx b/components/dashboard/src/components/RepositoryFinder.tsx index 352c9560dc678b..21fadab0cb42ea 100644 --- a/components/dashboard/src/components/RepositoryFinder.tsx +++ b/components/dashboard/src/components/RepositoryFinder.tsx @@ -6,7 +6,6 @@ import { User } from "@gitpod/gitpod-protocol"; import React, { useContext, useEffect, useState } from "react"; -import { Link } from "react-router-dom"; import { getGitpodService } from "../service/service"; import { UserContext } from "../user-context"; @@ -14,7 +13,7 @@ type SearchResult = string; type SearchData = SearchResult[]; const LOCAL_STORAGE_KEY = 'open-in-gitpod-search-data'; -const MAX_DISPLAYED_ITEMS = 15; +const MAX_DISPLAYED_ITEMS = 20; export default function RepositoryFinder(props: { initialQuery?: string }) { const { user } = useContext(UserContext); @@ -38,6 +37,10 @@ export default function RepositoryFinder(props: { initialQuery?: string }) { } } + useEffect(() => { + search(''); + }, []); + // Up/Down keyboard navigation between results const onKeyDown = (event: React.KeyboardEvent) => { if (!selectedSearchResult) { @@ -81,18 +84,9 @@ export default function RepositoryFinder(props: { initialQuery?: string }) {
- search(e.target.value)} onKeyDown={onKeyDown} /> + search(e.target.value)} onKeyDown={onKeyDown} />
- {searchQuery === '' && searchResults.length === 0 && -
- Paste a repository context URL, or start typing to see suggestions from: - -
} {searchResults.slice(0, MAX_DISPLAYED_ITEMS).map((result, index) => setSelectedSearchResult(result)}> {searchQuery.length < 2 @@ -157,10 +151,6 @@ async function actuallyRefreshSearchData(query: string, user: User | undefined): } async function findResults(query: string, onResults: (results: string[]) => void) { - if (!query) { - onResults([]); - return; - } const searchData = loadSearchData(); try { // If the query is a URL, and it's not present in the proposed results, "artificially" add it here. diff --git a/components/server/src/workspace/gitpod-server-impl.ts b/components/server/src/workspace/gitpod-server-impl.ts index 8982e5fed407a6..78f386ecd8de90 100644 --- a/components/server/src/workspace/gitpod-server-impl.ts +++ b/components/server/src/workspace/gitpod-server-impl.ts @@ -1029,7 +1029,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable { public async getSuggestedContextURLs(ctx: TraceContext): Promise { const user = this.checkUser("getSuggestedContextURLs"); - const suggestions: string[] = []; + const suggestions: Array<{ url: string, lastUse?: string }> = []; const logCtx: LogContext = { userId: user.id }; // Fetch all data sources in parallel for maximum speed (don't await in this scope before `Promise.allSettled(promises)` below!) @@ -1037,7 +1037,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable { // Example repositories promises.push(this.getFeaturedRepositories(ctx).then(exampleRepos => { - exampleRepos.forEach(r => suggestions.push(r.url)); + exampleRepos.forEach(r => suggestions.push({ url: r.url })); }).catch(error => { log.error(logCtx, 'Could not get example repositories', error); })); @@ -1046,7 +1046,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable { promises.push(this.getAuthProviders(ctx).then(authProviders => Promise.all(authProviders.map(async (p) => { try { const userRepos = await this.getProviderRepositoriesForUser(ctx, { provider: p.host }); - userRepos.forEach(r => suggestions.push(r.cloneUrl.replace(/\.git$/, ''))); + userRepos.forEach(r => suggestions.push({ url: r.cloneUrl.replace(/\.git$/, '') })); } catch (error) { log.debug(logCtx, 'Could not get user repositories from App for ' + p.host, error); } @@ -1064,7 +1064,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable { return; } const userRepos = await services.repositoryProvider.getUserRepos(user); - userRepos.forEach(r => suggestions.push(r.replace(/\.git$/, ''))); + userRepos.forEach(r => suggestions.push({ url: r.replace(/\.git$/, '') })); } catch (error) { log.debug(logCtx, 'Could not get user repositories from host ' + p.host, error); } @@ -1077,7 +1077,8 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable { workspaces.forEach(ws => { const repoUrl = Workspace.getFullRepositoryUrl(ws.workspace); if (repoUrl) { - suggestions.push(repoUrl); + const lastUse = WorkspaceInfo.lastActiveISODate(ws); + suggestions.push({ url: repoUrl, lastUse }); } }); }).catch(error => { @@ -1088,14 +1089,25 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable { const uniqueURLs = new Set(); return suggestions - .sort((a, b) => a.toLowerCase() > b.toLowerCase() ? 1 : -1) - .filter(r => { - if (uniqueURLs.has(r)) { + .sort((a, b) => { + // Most recently used first + if (b.lastUse || a.lastUse) { + const la = a.lastUse || ''; + const lb = b.lastUse || ''; + return la < lb ? 1 : (la === lb ? 0 : -1); + } + // Otherwise, alphasort + const ua = a.url.toLowerCase(); + const ub = b.url.toLowerCase(); + return ua > ub ? 1 : (ua === ub ? 0 : -1); + }) + .filter(s => { + if (uniqueURLs.has(s.url)) { return false; } - uniqueURLs.add(r); + uniqueURLs.add(s.url); return true; - }); + }).map(s => s.url); } public async setWorkspaceTimeout(ctx: TraceContext, workspaceId: string, duration: WorkspaceTimeoutDuration): Promise {