Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
liangfung committed Dec 15, 2024
1 parent 3dfbe34 commit 248d0c1
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 71 deletions.
2 changes: 1 addition & 1 deletion ee/tabby-schema/src/schema/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ impl Query {
}

Check warning on line 574 in ee/tabby-schema/src/schema/mod.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-schema/src/schema/mod.rs#L568-L574

Added lines #L568 - L574 were not covered by tests

async fn context_info(ctx: &Context) -> Result<ContextInfo> {
let user = check_user(ctx).await?;
let user = check_user_allow_auth_token(ctx).await?;

Check warning on line 577 in ee/tabby-schema/src/schema/mod.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-schema/src/schema/mod.rs#L577

Added line #L577 was not covered by tests
ctx.locator.context().read(Some(&user.policy)).await
}

Expand Down
24 changes: 16 additions & 8 deletions ee/tabby-ui/components/chat/chat-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ import type { Context } from 'tabby-chat-panel'

import { SLUG_TITLE_MAX_LENGTH } from '@/lib/constants'
import { useCopyToClipboard } from '@/lib/hooks/use-copy-to-clipboard'
import {
updateEnableActiveSelection,
updateEnableIndexedRepository
} from '@/lib/stores/chat-actions'
import { updateEnableActiveSelection } from '@/lib/stores/chat-actions'
import { useChatStore } from '@/lib/stores/chat-store'
import { useMutation } from '@/lib/tabby/gql'
import { setThreadPersistedMutation } from '@/lib/tabby/query'
Expand All @@ -24,7 +21,6 @@ import {
IconEye,
IconEyeOff,
IconFileText,
IconFolderGit,
IconRefresh,
IconRemove,
IconShare,
Expand All @@ -37,6 +33,7 @@ import { FooterText } from '@/components/footer'

import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip'
import { ChatContext } from './chat'
import { RepoSelect } from './repo-select'

export interface ChatPanelProps
extends Pick<UseChatHelpers, 'stop' | 'input' | 'setInput'> {
Expand Down Expand Up @@ -76,7 +73,11 @@ function ChatPanelRenderer(
removeRelevantContext,
activeSelection,
onCopyContent,
indexedRepository
indexedRepository,
selectedRepoId,
setSelectedRepoId,
repos,
fetchingRepos
} = React.useContext(ChatContext)
const enableActiveSelection = useChatStore(
state => state.enableActiveSelection
Expand Down Expand Up @@ -230,7 +231,14 @@ function ChatPanelRenderer(
<div className="border-t bg-background px-4 py-2 shadow-lg sm:space-y-4 sm:rounded-t-xl sm:border md:py-4">
<div className="flex flex-wrap gap-2">
<AnimatePresence presenceAffectsLayout>
{indexedRepository ? (
<RepoSelect
value={selectedRepoId}
onChange={setSelectedRepoId}
repos={repos}
workspaceRepoId={indexedRepository?.sourceId}
isInitializing={fetchingRepos}
/>
{/* {indexedRepository ? (
<motion.div
key="indexed-repository"
initial={{ opacity: 0, scale: 0.9, y: -5 }}
Expand Down Expand Up @@ -284,7 +292,7 @@ function ChatPanelRenderer(
</TooltipContent>
</Tooltip>
</motion.div>
) : null}
) : null} */}
{activeSelection ? (
<motion.div
key="active-selection"
Expand Down
36 changes: 33 additions & 3 deletions ee/tabby-ui/components/chat/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { useQuery } from 'urql'
import { ERROR_CODE_NOT_FOUND } from '@/lib/constants'
import {
CodeQueryInput,
ContextInfo,
ContextSourceKind,
CreateMessageInput,
InputMaybe,
MessageAttachmentCodeInput,
Expand All @@ -24,7 +26,7 @@ import { useLatest } from '@/lib/hooks/use-latest'
import { useThreadRun } from '@/lib/hooks/use-thread-run'
import { filename2prism } from '@/lib/language-utils'
import { useChatStore } from '@/lib/stores/chat-store'
import { resolveGitUrlQuery } from '@/lib/tabby/query'
import { contextInfoQuery, resolveGitUrlQuery } from '@/lib/tabby/query'
import { ExtendedCombinedError } from '@/lib/types'
import {
AssistantMessage,
Expand Down Expand Up @@ -67,6 +69,10 @@ type ChatContextValue = {
chatInputRef: RefObject<HTMLTextAreaElement>
supportsOnApplyInEditorV2: boolean
indexedRepository: ResolveGitUrlQuery['resolveGitUrl']
selectedRepoId: string | null
setSelectedRepoId: React.Dispatch<React.SetStateAction<string | null>>
repos: ContextInfo['sources']
fetchingRepos: boolean
}

export const ChatContext = React.createContext<ChatContextValue>(
Expand Down Expand Up @@ -143,7 +149,13 @@ function ChatRenderer(
const [activeSelection, setActiveSelection] = React.useState<Context | null>(
null
)
// gitUrl from workspace
const [gitUrl, setGitUrl] = React.useState<string | undefined>()
// sourceId
const [selectedRepoId, setSelectedRepoId] = React.useState<string | null>(
null
)

const enableActiveSelection = useChatStore(
state => state.enableActiveSelection
)
Expand All @@ -152,8 +164,22 @@ function ChatRenderer(
)

const chatPanelRef = React.useRef<ChatPanelRef>(null)
const [{ data: contextInfoData, fetching: fetchingSources }] = useQuery({
query: contextInfoQuery
})
const repos = React.useMemo(() => {
return (
contextInfoData?.contextInfo?.sources.filter(source => {
return [
ContextSourceKind.Git,
ContextSourceKind.Github,
ContextSourceKind.Gitlab
].includes(source.sourceKind)
}) ?? []
)
}, [contextInfoData])

const [{ data }] = useQuery({
const [{ data: resolvedGitUrl }] = useQuery({
query: resolveGitUrlQuery,
variables: {
gitUrl: gitUrl as string
Expand Down Expand Up @@ -586,7 +612,11 @@ function ChatRenderer(
chatInputRef,
activeSelection,
supportsOnApplyInEditorV2,
indexedRepository: gitUrl ? data?.resolveGitUrl : undefined
indexedRepository: gitUrl ? resolvedGitUrl?.resolveGitUrl : undefined,
selectedRepoId,
setSelectedRepoId,
repos,
fetchingRepos: fetchingSources
}}
>
<div className="flex justify-center overflow-x-hidden">
Expand Down
12 changes: 3 additions & 9 deletions ee/tabby-ui/components/chat/prompt-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import {
SearchableSelectOption,
SearchableSelectTextarea
} from '@/components/searchable-select'
import { RepoSelect } from './repo-select'

export interface PromptProps
extends Pick<UseChatHelpers, 'input' | 'setInput'> {
Expand Down Expand Up @@ -199,15 +198,15 @@ function PromptFormRenderer(
return (
<>
<SearchableSelectAnchor>
<div className="relative flex max-h-60 w-full grow flex-col overflow-hidden bg-background pr-8 sm:rounded-md sm:border sm:pr-12">
{/* <span
<div className="relative flex max-h-60 w-full grow flex-col overflow-hidden bg-background px-8 sm:rounded-md sm:border sm:px-12">
<span
className={cn(
buttonVariants({ size: 'sm', variant: 'ghost' }),
'absolute left-0 top-4 h-8 w-8 rounded-full bg-background p-0 hover:bg-background sm:left-4'
)}
>
<IconEdit />
</span> */}
</span>
<SearchableSelectTextarea
tabIndex={0}
rows={1}
Expand Down Expand Up @@ -305,11 +304,6 @@ function PromptFormRenderer(
)
}}
</SearchableSelect>
<RepoSelect
value={undefined}
onChange={() => {}}
models={['1', '2']}
/>
</form>
)
}
Expand Down
145 changes: 95 additions & 50 deletions ee/tabby-ui/components/chat/repo-select.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,50 @@
import { Maybe } from '@/lib/gql/generates/graphql'
import { ContextInfo } from '@/lib/gql/generates/graphql'
import { cn } from '@/lib/utils'
import { Badge } from '@/components/ui/badge'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuTrigger
} from '@/components/ui/dropdown-menu'
import { IconCheck, IconFolderGit } from '@/components/ui/icons'
import {
IconCheck,
IconChevronUpDown,
IconFolderGit,
IconRemove
} from '@/components/ui/icons'
import { Skeleton } from '@/components/ui/skeleton'
import LoadingWrapper from '@/components/loading-wrapper'

import { Badge } from '../ui/badge'
import { Button } from '../ui/button'

interface RepoSelectProps {
// todo rename
models: Maybe<Array<string>> | undefined
value: string | undefined
onChange: (v: string) => void
repos: ContextInfo['sources']
value: string | null | undefined
onChange: (v: string | null) => void
isInitializing?: boolean
// sourceId
workspaceRepoId?: string
}

export function RepoSelect({
models,
repos,
value,
onChange,
isInitializing
isInitializing,
workspaceRepoId
}: RepoSelectProps) {
const onModelSelect = (v: string) => {
const onSelectRepo = (v: string) => {
onChange(v)
// todo input focus
}

const isWorkspaceRepo = !!workspaceRepoId && workspaceRepoId === value
const selectedRepoName = repos?.find(
repo => repo.sourceId === value
)?.sourceName

return (
<LoadingWrapper
loading={isInitializing}
Expand All @@ -41,57 +54,89 @@ export function RepoSelect({
</div>
}
>
{!!models?.length && (
<DropdownMenu>
<DropdownMenuTrigger>
<Badge
variant="outline"
className="inline-flex h-7 flex-nowrap items-center gap-1 overflow-hidden rounded-md text-sm font-semibold"
>
<IconFolderGit />
{/* FIXME */}
{/* {value} */}
TabbyML/tabby
</Badge>
<DropdownMenu>
<Badge
variant="outline"
className="h-7 items-center gap-1 overflow-hidden rounded-md text-sm font-semibold pr-0 min-w-[8rem]"
>
<DropdownMenuTrigger className="outline-none" asChild>
<div className="cursor-pointer flex-1 flex items-center gap-1.5 truncate break-all">
<IconFolderGit className="shrink-0" />
<div className="flex-1 flex items-center gap-1.5">
<span
className={cn({
'text-muted-foreground': !selectedRepoName
})}
>
{selectedRepoName || 'Select repo...'}
</span>
{isWorkspaceRepo && (
<span className="shrink-0 text-muted-foreground">
Repo in workspace
</span>
)}
</div>
{!value && <IconChevronUpDown className="shrink-0" />}
</div>
</DropdownMenuTrigger>
<DropdownMenuContent
side="bottom"
align="start"
className="dropdown-menu max-h-[30vh] min-w-[20rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-2 text-popover-foreground shadow animate-in"
>
<DropdownMenuRadioGroup value={value} onValueChange={onChange}>
{models.map(model => {
const isSelected = model === value
return (
<DropdownMenuRadioItem
onClick={e => {
onModelSelect(model)
e.stopPropagation()
}}
value={model}
key={model}
className="cursor-pointer py-2 pl-3"
>
{!!value && (
<Button
type="button"
size="icon"
variant="ghost"
className="h-7 w-7 shrink-0 rounded-l-none"
onClick={e => {
console.log('eeeeeeee')
e.preventDefault()
e.stopPropagation()
onChange(null)
}}
>
<IconRemove />
</Button>
)}
</Badge>
<DropdownMenuContent
side="top"
align="start"
className="dropdown-menu max-h-[30vh] min-w-[20rem] max-w-full overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-2 text-popover-foreground shadow animate-in"
>
<DropdownMenuRadioGroup>
{repos.map(repo => {
const isSelected = repo.sourceId === value
return (
<DropdownMenuRadioItem
value={repo.sourceId}
key={repo.sourceId}
className="cursor-pointer py-2 pl-3 flex items-center"
onSelect={() => onSelectRepo(repo.sourceId)}
>
<div className="flex-1 truncate flex items-center gap-2">
<IconCheck
className={cn(
'mr-2 shrink-0',
model === value ? 'opacity-100' : 'opacity-0'
'shrink-0',
repo.sourceId === value ? 'opacity-100' : 'opacity-0'
)}
/>
<span
className={cn({
'font-medium': isSelected
})}
>
{model}
{repo.sourceName}
</span>
</div>
{repo.sourceId === workspaceRepoId && (
<span className="text-muted-foreground ml-1.5 shrink-0">
Repo in workspace
</span>
</DropdownMenuRadioItem>
)
})}
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
)}
)}
</DropdownMenuRadioItem>
)
})}
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
</LoadingWrapper>
)
}

0 comments on commit 248d0c1

Please sign in to comment.