Skip to content
This repository was archived by the owner on Sep 30, 2024. It is now read-only.

Commit c0d82e0

Browse files
authored
svelte: Use parallel data loading (#60303)
1 parent 296ce96 commit c0d82e0

File tree

32 files changed

+354
-321
lines changed

32 files changed

+354
-321
lines changed

client/shared/src/search/query/completion-utils.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
import { escapeRegExp } from 'lodash'
66

7-
import type { RepositoryMatch } from '../stream'
8-
97
import { escapeSpaces, FILTERS, type FilterType, isNegatableFilter } from './filters'
108

119
export const PREDICATE_REGEX = /^([.A-Za-z]+)\((.*?)\)?$/
@@ -23,7 +21,7 @@ export const regexInsertText = (value: string): string => {
2321
* repositoryInsertText escapes the provides value so that it can be used as a
2422
* value for the `repo:` filter.
2523
*/
26-
export const repositoryInsertText = ({ repository }: RepositoryMatch): string => regexInsertText(repository)
24+
export const repositoryInsertText = ({ repository }: { repository: string }): string => regexInsertText(repository)
2725

2826
/**
2927
* Given a list of filter types, this function returns a list of objects which

client/web-sveltekit/src/lib/repo/api/tree.ts

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ import type { TreeProvider } from '$lib/TreeView'
77
const MAX_FILE_TREE_ENTRIES = 1000
88

99
const treeEntriesQuery = gql`
10-
query TreeEntries($repoID: ID!, $commitID: String!, $filePath: String!, $first: Int) {
11-
node(id: $repoID) {
10+
query TreeEntries($repoName: String!, $revision: String!, $filePath: String!, $first: Int) {
11+
repository(name: $repoName) {
1212
id
1313
... on Repository {
14-
commit(rev: $commitID) {
14+
commit(rev: $revision) {
1515
...GitCommitFieldsWithTree
1616
}
1717
}
@@ -48,10 +48,10 @@ export async function fetchTreeEntries(args: TreeEntriesVariables): Promise<GitC
4848
}
4949
// mightContainPrivateInfo: true,
5050
)
51-
if (data.node?.__typename !== 'Repository' || !data.node.commit) {
51+
if (!data.repository?.commit) {
5252
throw new Error('Unable to fetch repository information')
5353
}
54-
return data.node.commit
54+
return data.repository.commit
5555
}
5656

5757
export const NODE_LIMIT: unique symbol = Symbol()
@@ -62,17 +62,17 @@ type ExpandableFileTreeNodeValues = TreeEntryFields
6262
export type FileTreeNodeValue = ExpandableFileTreeNodeValues | typeof NODE_LIMIT
6363

6464
export async function fetchSidebarFileTree({
65-
repoID,
66-
commitID,
65+
repoName,
66+
revision,
6767
filePath,
6868
}: {
69-
repoID: Scalars['ID']['input']
70-
commitID: string
69+
repoName: Scalars['ID']['input']
70+
revision: string
7171
filePath: string
7272
}): Promise<{ root: TreeRoot; values: FileTreeNodeValue[] }> {
7373
const result = await fetchTreeEntries({
74-
repoID,
75-
commitID,
74+
repoName,
75+
revision,
7676
filePath,
7777
first: MAX_FILE_TREE_ENTRIES,
7878
})
@@ -88,17 +88,17 @@ export async function fetchSidebarFileTree({
8888
}
8989

9090
export type FileTreeLoader = (args: {
91-
repoID: Scalars['ID']['input']
92-
commitID: string
91+
repoName: string
92+
revision: string
9393
filePath: string
9494
parent?: FileTreeProvider
9595
}) => Promise<FileTreeProvider>
9696

9797
interface FileTreeProviderArgs {
9898
root: NonNullable<GitCommitFieldsWithTree['tree']>
9999
values: FileTreeNodeValue[]
100-
repoID: Scalars['ID']['input']
101-
commitID: string
100+
repoName: string
101+
revision: string
102102
loader: FileTreeLoader
103103
parent?: TreeProvider<FileTreeNodeValue>
104104
}
@@ -110,8 +110,8 @@ export class FileTreeProvider implements TreeProvider<FileTreeNodeValue> {
110110
return this.args.root
111111
}
112112

113-
public getRepoID(): Scalars['ID']['input'] {
114-
return this.args.repoID
113+
public getRepoName(): string {
114+
return this.args.repoName
115115
}
116116

117117
public getEntries(): FileTreeNodeValue[] {
@@ -130,8 +130,8 @@ export class FileTreeProvider implements TreeProvider<FileTreeNodeValue> {
130130
}
131131

132132
return this.args.loader({
133-
repoID: this.args.repoID,
134-
commitID: this.args.commitID,
133+
repoName: this.args.repoName,
134+
revision: this.args.revision,
135135
filePath: entry.path,
136136
parent: this,
137137
})
@@ -140,8 +140,8 @@ export class FileTreeProvider implements TreeProvider<FileTreeNodeValue> {
140140
public async fetchParent(): Promise<FileTreeProvider> {
141141
const parentPath = dirname(this.args.root.path)
142142
return this.args.loader({
143-
repoID: this.args.repoID,
144-
commitID: this.args.commitID,
143+
repoName: this.args.repoName,
144+
revision: this.args.revision,
145145
filePath: parentPath,
146146
})
147147
}

client/web-sveltekit/src/lib/repo/utils.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,24 @@ export function getFileURL(repoURL: string, file: { canonicalURL: string }): str
4343
// TODO: Find out whether there is a safer way to do this
4444
return repoURL + file.canonicalURL.slice(file.canonicalURL.indexOf('/-/'))
4545
}
46+
47+
/**
48+
* This function is supposed to be used in repository data loaders.
49+
*
50+
* In order to ensure data consistency when navigating between repository pages, we have
51+
* to ensure that the pages fetch data for the same revision. If a revision specifier is
52+
* present in the URL and is a commit ID, we can use it directly. If it's a branch name,
53+
* tag name or is missing, we have to wait for the parent loader to resolve the revision
54+
* to a commit ID.
55+
*/
56+
export async function resolveRevision(
57+
parent: () => Promise<{ resolvedRevision: ResolvedRevision }>,
58+
revisionFromURL: string | undefined
59+
): Promise<string> {
60+
// There is a chance that a commit ID is used as a branch or tag name,
61+
// but it's unlikely. Avoiding waterfall requests is worth the risk.
62+
if (revisionFromURL && /[0-9a-f]{40}/.test(revisionFromURL)) {
63+
return revisionFromURL
64+
}
65+
return (await parent()).resolvedRevision.commitID
66+
}

client/web-sveltekit/src/lib/search/utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type FilterGroups = Record<Filter['kind'], Filter[]>
2020

2121
export function groupFilters(filters: Filter[] | null | undefined): FilterGroups {
2222
const groupedFilters: FilterGroups = {
23+
type: [],
2324
file: [],
2425
repo: [],
2526
lang: [],

client/web-sveltekit/src/routes/[...repo=reporev]/(validrev)/(code)/+layout.svelte

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
1414
import type { LayoutData, Snapshot } from './$types'
1515
import FileTree from './FileTree.svelte'
16-
import type { Scalars } from '$lib/graphql-operations'
1716
import type { GitHistory_HistoryConnection } from './layout.gql'
1817
import Tabs from '$lib/Tabs.svelte'
1918
import TabPanel from '$lib/TabPanel.svelte'
@@ -61,7 +60,7 @@
6160
})
6261
)
6362
64-
async function updateFileTreeProvider(repoID: Scalars['ID']['input'], commitID: string, parentPath: string) {
63+
async function updateFileTreeProvider(repoName: string, revision: string, parentPath: string) {
6564
const result = await data.fileTree
6665
if (!result) {
6766
treeProvider = null
@@ -70,18 +69,14 @@
7069
const { root, values } = result
7170
7271
// Do nothing if update was called with new arguments in the meantime
73-
if (
74-
repoID !== data.resolvedRevision.repo.id ||
75-
commitID !== data.resolvedRevision.commitID ||
76-
parentPath !== data.parentPath
77-
) {
72+
if (repoName !== data.repoName || revision !== (data.revision ?? '') || parentPath !== data.parentPath) {
7873
return
7974
}
8075
treeProvider = new FileTreeProvider({
8176
root,
8277
values,
83-
repoID,
84-
commitID,
78+
repoName,
79+
revision,
8580
loader: fileTreeLoader,
8681
})
8782
}
@@ -111,12 +106,10 @@
111106
let historyPanel: HistoryPanel
112107
let rootElement: HTMLElement | null = null
113108
114-
$: ({ revision, parentPath, resolvedRevision } = data)
115-
$: commitID = resolvedRevision.commitID
116-
$: repoID = resolvedRevision.repo.id
109+
$: ({ revision = '', parentPath, repoName } = data)
117110
// Only update the file tree provider (which causes the tree to rerender) when repo, revision/commit or file path
118111
// update
119-
$: updateFileTreeProvider(repoID, commitID, parentPath)
112+
$: updateFileTreeProvider(repoName, revision, parentPath)
120113
$: commitHistoryQuery = data.commitHistory
121114
let commitHistory: GitHistory_HistoryConnection | null
122115
$: if (commitHistoryQuery) {
@@ -125,10 +118,7 @@
125118
// file/folder until the new commit history is loaded.
126119
commitHistory = null
127120
}
128-
$: commitHistory =
129-
$commitHistoryQuery?.data.node?.__typename === 'Repository'
130-
? $commitHistoryQuery.data.node.commit?.ancestors ?? null
131-
: null
121+
$: commitHistory = $commitHistoryQuery?.data?.repository?.commit?.ancestors ?? null
132122
133123
const sidebarSize = getSeparatorPosition('repo-sidebar', 0.2)
134124
$: sidebarWidth = `max(200px, ${$sidebarSize * 100}%)`

client/web-sveltekit/src/routes/[...repo=reporev]/(validrev)/(code)/+layout.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { dirname } from 'path'
22

33
import { browser } from '$app/environment'
4+
import { getGraphQLClient } from '$lib/graphql'
45
import { fetchSidebarFileTree } from '$lib/repo/api/tree'
6+
import { parseRepoRevision } from '$lib/shared'
57

68
import type { LayoutLoad } from './$types'
79
import { GitHistoryQuery } from './layout.gql'
@@ -27,22 +29,23 @@ if (browser) {
2729
}
2830

2931
export const load: LayoutLoad = async ({ parent, params }) => {
30-
const { resolvedRevision, repoName, graphqlClient } = await parent()
32+
const client = await getGraphQLClient()
33+
const { repoName, revision = '' } = parseRepoRevision(params.repo)
3134
const parentPath = getRootPath(repoName, params.path ? dirname(params.path) : REPO_ROOT)
3235

3336
// Fetches the most recent commits for current blob, tree or repo root
34-
const commitHistory = graphqlClient.watchQuery({
37+
const commitHistory = client.watchQuery({
3538
query: GitHistoryQuery,
3639
variables: {
37-
repo: resolvedRevision.repo.id,
38-
revspec: resolvedRevision.commitID,
40+
repoName,
41+
revspec: revision,
3942
filePath: params.path ?? '',
4043
first: HISTORY_COMMITS_PER_PAGE,
4144
afterCursor: null,
4245
},
4346
notifyOnNetworkStatusChange: true,
4447
})
45-
if (!graphqlClient.readQuery({ query: GitHistoryQuery, variables: commitHistory.variables })) {
48+
if (!client.readQuery({ query: GitHistoryQuery, variables: commitHistory.variables })) {
4649
// Eagerly fetch data if it isn't in the cache already. This ensures that the data is fetched
4750
// as soon as possible, not only after the layout subscribes to the query.
4851
commitHistory.refetch()
@@ -52,8 +55,8 @@ export const load: LayoutLoad = async ({ parent, params }) => {
5255
parentPath,
5356
commitHistory,
5457
fileTree: fetchSidebarFileTree({
55-
repoID: resolvedRevision.repo.id,
56-
commitID: resolvedRevision.commitID,
58+
repoName,
59+
revision,
5760
filePath: parentPath,
5861
}),
5962
}

client/web-sveltekit/src/routes/[...repo=reporev]/(validrev)/(code)/+page.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ export const load: PageLoad = async ({ parent }) => {
2323
})
2424
.then(result => {
2525
if (result.data.node?.__typename !== 'Repository') {
26+
// This page will never render when the repository is not found.
27+
// The (validrev) data loader will render an error page instead.
28+
// Still, this error will show up as an unhandled promise rejection
29+
// in the console. We should find a better way to handle this.
2630
throw new Error('Expected Repository')
2731
}
2832
return result.data.node.commit?.blob ?? null

client/web-sveltekit/src/routes/[...repo=reporev]/(validrev)/(code)/-/blob/[...path]/+page.svelte

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,22 @@
2424
2525
export let data: PageData
2626
27-
const {
27+
// We use the latest value here because we want to keep showing the old document while loading
28+
// the new one.
29+
const { loading, combinedBlobData, set: setBlobData } = createBlobDataHandler()
30+
let selectedPosition: LineOrPositionOrRange | null = null
31+
32+
$: ({
2833
revision,
2934
resolvedRevision: { commitID },
3035
repoName,
3136
filePath,
3237
settings,
3338
graphqlClient,
34-
} = data
35-
// We use the latest value here because we want to keep showing the old document while loading
36-
// the new one.
37-
const { loading, combinedBlobData, set: setBlobData } = createBlobDataHandler()
38-
let selectedPosition: LineOrPositionOrRange | null = null
39-
39+
} = data)
4040
$: setBlobData(data.blob, data.highlights)
41-
$: blobData = $combinedBlobData.blob
42-
$: formatted = !!blobData?.richHTML
41+
$: ({ blob, highlights = '' } = $combinedBlobData)
42+
$: formatted = !!blob?.richHTML
4343
$: showRaw = $page.url.searchParams.get('view') === 'raw'
4444
$: codeIntelAPI = createCodeIntelAPI({
4545
settings: setting => (isErrorLike(settings.final) ? undefined : settings.final?.[setting]),
@@ -53,7 +53,7 @@
5353
</script>
5454

5555
<svelte:head>
56-
<title>{data.filePath} - {data.displayRepoName} - Sourcegraph</title>
56+
<title>{filePath} - {data.displayRepoName} - Sourcegraph</title>
5757
</svelte:head>
5858

5959
<FileHeader>
@@ -68,7 +68,7 @@
6868
{#if formatted}
6969
<FormatAction />
7070
{/if}
71-
<Permalink commitID={data.resolvedRevision.commitID} />
71+
<Permalink {commitID} />
7272
{/if}
7373
</svelte:fragment>
7474
</FileHeader>
@@ -84,21 +84,21 @@
8484
Unable to load iff
8585
{/if}
8686
{/await}
87-
{:else if blobData}
88-
{#if blobData.richHTML && !showRaw}
87+
{:else if blob}
88+
{#if blob.richHTML && !showRaw}
8989
<div class="rich">
90-
{@html blobData.richHTML}
90+
{@html blob.richHTML}
9191
</div>
9292
{:else}
9393
<CodeMirrorBlob
9494
blobInfo={{
95-
...blobData,
95+
...blob,
9696
revision: revision ?? '',
9797
commitID,
9898
repoName: repoName,
9999
filePath,
100100
}}
101-
highlights={$combinedBlobData.highlights || ''}
101+
{highlights}
102102
wrapLines={$lineWrap}
103103
selectedLines={selectedPosition?.line ? selectedPosition : null}
104104
on:selectline={event => {

0 commit comments

Comments
 (0)