Skip to content

Commit

Permalink
feat(ui): integrate repository list (#1975)
Browse files Browse the repository at this point in the history
* feat(ui): integrate repository list

* format

* gql
  • Loading branch information
liangfung authored Apr 26, 2024
1 parent edb23ff commit 5124086
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 68 deletions.
9 changes: 4 additions & 5 deletions ee/tabby-ui/app/files/components/file-directory-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { Table, TableBody, TableCell, TableRow } from '@/components/ui/table'
import { BlobHeader } from './blob-header'
import { TFileTreeNode } from './file-tree'
import { SourceCodeBrowserContext, TFileMapItem } from './source-code-browser'
import { resolveFileNameFromPath } from './utils'

interface DirectoryViewProps extends React.HTMLAttributes<HTMLDivElement> {
loading: boolean
Expand Down Expand Up @@ -87,7 +86,7 @@ const DirectoryView: React.FC<DirectoryViewProps> = ({
onClick={e => onClickFile(file)}
className="cursor-pointer px-1 py-2 hover:text-primary hover:underline"
>
{resolveFileNameFromPath(file.fullPath)}
{file.name}
</span>
</div>
</TableCell>
Expand Down Expand Up @@ -129,9 +128,9 @@ function getCurrentDirFromTree(
} else {
let pathSegments = path.split('/')
let currentNodes: TFileTreeNode[] = treeData
while (pathSegments.length) {
let name = pathSegments.shift()
let node = find<TFileTreeNode>(currentNodes, t => t.name === name)
for (let i = 1; i < pathSegments.length; i++) {
const path = pathSegments.slice(0, i + 1).join('/')
let node = find<TFileTreeNode>(currentNodes, t => t.fullPath === path)
if (node?.children) {
currentNodes = node?.children
} else {
Expand Down
41 changes: 27 additions & 14 deletions ee/tabby-ui/app/files/components/file-tree-header.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client'

import React, { useContext } from 'react'
import { isEmpty } from 'lodash-es'
import { useQuery } from 'urql'

import { graphql } from '@/lib/gql/generates'
Expand Down Expand Up @@ -32,9 +33,12 @@ import { useTopbarProgress } from '@/components/topbar-progress-indicator'
import { SourceCodeBrowserContext, TFileMap } from './source-code-browser'
import {
fetchEntriesFromPath,
generatePathPrefixFromPath,
getDirectoriesFromBasename,
key2RepositoryKind,
resolveFileNameFromPath,
resolveRepoNameFromPath
resolveRepoIdFromPath,
resolveRepoKindFromPath
} from './utils'

interface FileTreeHeaderProps extends React.HTMLAttributes<HTMLDivElement> {}
Expand All @@ -47,8 +51,8 @@ type SearchOption = {
}

const repositorySearch = graphql(/* GraphQL */ `
query RepositorySearch($repositoryName: String!, $pattern: String!) {
repositorySearch(repositoryName: $repositoryName, pattern: $pattern) {
query RepositorySearch($kind: RepositoryKind!, $id: ID!, $pattern: String!) {
repositorySearch(kind: $kind, id: $id, pattern: $pattern) {
type
path
indices
Expand All @@ -66,10 +70,18 @@ const FileTreeHeader: React.FC<FileTreeHeaderProps> = ({
setActivePath,
initialized,
updateFileMap,
setExpandedKeys
setExpandedKeys,
fileMap
} = useContext(SourceCodeBrowserContext)
const { setProgress } = useTopbarProgress()
const curerntRepoName = resolveRepoNameFromPath(activePath)

const prefix = generatePathPrefixFromPath(activePath)
const repoKind = resolveRepoKindFromPath(activePath)
const repoId = resolveRepoIdFromPath(activePath)
const curerntRepoName = React.useMemo(() => {
if (!prefix || isEmpty(fileMap)) return undefined
return fileMap?.[prefix]?.name
}, [prefix, fileMap])

const inputRef = React.useRef<HTMLInputElement>(null)
const [input, setInput] = React.useState<string>()
Expand All @@ -83,10 +95,11 @@ const FileTreeHeader: React.FC<FileTreeHeaderProps> = ({
const [{ data: repositorySearchData }] = useQuery({
query: repositorySearch,
variables: {
repositoryName: curerntRepoName,
kind: key2RepositoryKind(repoKind),
id: repoId,
pattern: repositorySearchPattern ?? ''
},
pause: !curerntRepoName || !repositorySearchPattern
pause: !prefix || !repositorySearchPattern
})

React.useEffect(() => {
Expand Down Expand Up @@ -122,7 +135,7 @@ const FileTreeHeader: React.FC<FileTreeHeaderProps> = ({
const path = value.path
if (!path) return

const fullPath = `${curerntRepoName}/${path}`
const fullPath = `${prefix}/${path}`
try {
setProgress(true)
const entries = await fetchEntriesFromPath(fullPath)
Expand All @@ -131,7 +144,7 @@ const FileTreeHeader: React.FC<FileTreeHeaderProps> = ({
const patchMap: TFileMap = {}
// fetch dirs
for (const entry of entries) {
const path = `${curerntRepoName}/${entry.basename}`
const path = `${prefix}/${entry.basename}`
patchMap[path] = {
file: entry,
name: resolveFileNameFromPath(path),
Expand All @@ -140,7 +153,7 @@ const FileTreeHeader: React.FC<FileTreeHeaderProps> = ({
}
}
const expandedKeys = initialExpandedDirs.map(dir =>
[curerntRepoName, dir].filter(Boolean).join('/')
[prefix, dir].filter(Boolean).join('/')
)
if (patchMap) {
updateFileMap(patchMap)
Expand Down Expand Up @@ -194,7 +207,7 @@ const FileTreeHeader: React.FC<FileTreeHeaderProps> = ({
<Select
disabled={!initialized}
onValueChange={onSelectRepo}
value={curerntRepoName}
value={prefix}
>
<SelectTrigger>
<SelectValue>
Expand All @@ -208,7 +221,7 @@ const FileTreeHeader: React.FC<FileTreeHeaderProps> = ({
</div>
</SelectValue>
</SelectTrigger>
<SelectContent>
<SelectContent className="max-h-[50vh] overflow-y-auto">
{noIndexedRepo ? (
<SelectItem isPlaceHolder value="" disabled>
No indexed repository
Expand All @@ -217,7 +230,7 @@ const FileTreeHeader: React.FC<FileTreeHeaderProps> = ({
<>
{fileTreeData?.map(repo => {
return (
<SelectItem key={repo.fullPath} value={repo.name}>
<SelectItem key={repo.fullPath} value={repo.fullPath}>
{repo.name}
</SelectItem>
)
Expand Down Expand Up @@ -298,7 +311,7 @@ const FileTreeHeader: React.FC<FileTreeHeaderProps> = ({
side="bottom"
onOpenAutoFocus={e => e.preventDefault()}
style={{ width: '50vw', maxWidth: 700 }}
className="max-h-[50vh] overflow-y-scroll"
className="max-h-[50vh] overflow-y-auto"
>
<>
{options?.length ? (
Expand Down
6 changes: 3 additions & 3 deletions ee/tabby-ui/app/files/components/file-tree-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useScrollTop } from '@/lib/hooks/use-scroll-top'
import { FileTree, TFileTreeNode } from './file-tree'
import { FileTreeHeader } from './file-tree-header'
import { SourceCodeBrowserContext } from './source-code-browser'
import { resolveRepoNameFromPath } from './utils'
import { generatePathPrefixFromPath } from './utils'

interface FileTreePanelProps extends React.HTMLAttributes<HTMLDivElement> {}

Expand All @@ -29,8 +29,8 @@ export const FileTreePanel: React.FC<FileTreePanelProps> = () => {
}

const currentFileTreeData = React.useMemo(() => {
const repoName = resolveRepoNameFromPath(activePath)
const repo = fileTreeData.find(treeNode => treeNode.name === repoName)
const repoPrefix = generatePathPrefixFromPath(activePath)
const repo = fileTreeData.find(treeNode => treeNode.fullPath === repoPrefix)
return repo?.children ?? []
}, [activePath, fileTreeData])

Expand Down
20 changes: 12 additions & 8 deletions ee/tabby-ui/app/files/components/file-tree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ import {
import { Skeleton } from '@/components/ui/skeleton'

import { TFileMap } from './source-code-browser'
import { resolveFileNameFromPath, resolveRepoNameFromPath } from './utils'
import {
generatePathPrefixFromPath,
resolveFileNameFromPath,
resolveRepoNameFromPath
} from './utils'

type TFileTreeNode = {
name: string
Expand Down Expand Up @@ -316,7 +320,7 @@ const DirectoryTreeNode: React.FC<DirectoryTreeNodeProps> = ({
const FileTreeRenderer: React.FC = () => {
const { initialized, activePath, fileMap, fileTreeData } =
React.useContext(FileTreeContext)
const repoName = resolveRepoNameFromPath(activePath)
const repoPrefix = generatePathPrefixFromPath(activePath)

if (!initialized) return <FileTreeSkeleton />

Expand All @@ -327,13 +331,13 @@ const FileTreeRenderer: React.FC = () => {
</div>
)

if (repoName && !fileTreeData?.length) {
if (repoPrefix && !fileTreeData?.length) {
return (
<div className="flex h-full items-center justify-center">No Data</div>
)
}

if (!repoName) {
if (!repoPrefix) {
return null
}

Expand Down Expand Up @@ -371,16 +375,16 @@ function mapToFileTree(fileMap: TFileMap | undefined): TFileTreeNode[] {
const pathSegments = fileKey.split('/')
let currentNode = tree

for (let i = 0; i < pathSegments.length; i++) {
const segment = pathSegments[i]
const existingNode = currentNode?.find(node => node.name === segment)
for (let i = 1; i < pathSegments.length; i++) {
const p = pathSegments.slice(0, i + 1).join('/')
const existingNode = currentNode?.find(node => node.fullPath === p)

if (existingNode) {
currentNode = existingNode.children || []
} else {
const newNode: TFileTreeNode = {
file: file.file,
name: segment,
name: file.name,
fullPath: fileKey,
children: []
}
Expand Down
Loading

0 comments on commit 5124086

Please sign in to comment.