Skip to content

Commit

Permalink
fix(ui): fix the error handling for thread editing (#3391)
Browse files Browse the repository at this point in the history
* fix(webserver): forbid empty content message update

* fix(ui): fix the error handling for thread editing

---------

Co-authored-by: Wei Zhang <[email protected]>
  • Loading branch information
liangfung and zwpaper authored Nov 8, 2024
1 parent 600acb5 commit a7f65b5
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 27 deletions.
28 changes: 17 additions & 11 deletions ee/tabby-ui/app/search/components/assistant-message-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ import * as z from 'zod'

import { MARKDOWN_CITATION_REGEX } from '@/lib/constants/regex'
import { MessageAttachmentCode } from '@/lib/gql/generates/graphql'
import { AttachmentDocItem, RelevantCodeContext } from '@/lib/types'
import { makeFormErrorHandler } from '@/lib/tabby/gql'
import {
AttachmentDocItem,
ExtendedCombinedError,
RelevantCodeContext
} from '@/lib/types'
import {
cn,
formatLineHashForCodeBrowser,
Expand Down Expand Up @@ -207,9 +212,9 @@ export function AssistantMessageSection({
}

const handleUpdateAssistantMessage = async (message: ConversationMessage) => {
const errorMessage = await onUpdateMessage(message)
if (errorMessage) {
return errorMessage
const error = await onUpdateMessage(message)
if (error) {
return error
} else {
setIsEditing(false)
}
Expand Down Expand Up @@ -518,7 +523,9 @@ function MessageContentForm({
}: {
message: ConversationMessage
onCancel: () => void
onSubmit: (newMessage: ConversationMessage) => Promise<string | void>
onSubmit: (
newMessage: ConversationMessage
) => Promise<ExtendedCombinedError | void>
}) {
const formSchema = z.object({
content: z.string().trim()
Expand All @@ -528,17 +535,16 @@ function MessageContentForm({
defaultValues: { content: message.content }
})
const { isSubmitting } = form.formState
const { content } = form.watch()
const isEmptyContent = !content || isEmpty(content.trim())
const [draftMessage] = useState<ConversationMessage>(message)

const handleSubmit = async (values: z.infer<typeof formSchema>) => {
const errorMessage = await onSubmit({
const error = await onSubmit({
...draftMessage,
content: values.content
})
if (errorMessage) {
form.setError('root', { message: errorMessage })

if (error) {
makeFormErrorHandler(form)(error)
}
}

Expand Down Expand Up @@ -576,7 +582,7 @@ function MessageContentForm({
>
Cancel
</Button>
<Button type="submit" disabled={isEmptyContent || isSubmitting}>
<Button type="submit" disabled={isSubmitting}>
{isSubmitting && (
<IconSpinner className="mr-2 h-4 w-4 animate-spin" />
)}
Expand Down
16 changes: 10 additions & 6 deletions ee/tabby-ui/app/search/components/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import { useMe } from '@/lib/hooks/use-me'
import { useSelectedModel } from '@/lib/hooks/use-models'
import useRouterStuff from '@/lib/hooks/use-router-stuff'
import { useIsChatEnabled } from '@/lib/hooks/use-server-info'
import { ExtendedCombinedError, useThreadRun } from '@/lib/hooks/use-thread-run'
import { useThreadRun } from '@/lib/hooks/use-thread-run'
import { updateSelectedModel } from '@/lib/stores/chat-actions'
import { clearHomeScrollPosition } from '@/lib/stores/scroll-store'
import { useMutation } from '@/lib/tabby/gql'
Expand All @@ -53,6 +53,7 @@ import {
import {
AttachmentCodeItem,
AttachmentDocItem,
ExtendedCombinedError,
ThreadRunContexts
} from '@/lib/types'
import {
Expand Down Expand Up @@ -116,7 +117,9 @@ type SearchContextValue = {
fetchingContextInfo: boolean
onDeleteMessage: (id: string) => void
isThreadOwner: boolean
onUpdateMessage: (message: ConversationMessage) => Promise<string | undefined>
onUpdateMessage: (
message: ConversationMessage
) => Promise<ExtendedCombinedError | undefined>
}

export const SearchContext = createContext<SearchContextValue>(
Expand Down Expand Up @@ -167,7 +170,9 @@ export function Search() {

const updateThreadMessage = useMutation(updateThreadMessageMutation)

const onUpdateMessage = async (message: ConversationMessage) => {
const onUpdateMessage = async (
message: ConversationMessage
): Promise<ExtendedCombinedError | undefined> => {
const messageIndex = messages.findIndex(o => o.id === message.id)
if (messageIndex > -1 && threadId) {
// 1. call api
Expand All @@ -186,11 +191,10 @@ export function Search() {
return newMessages
})
} else {
// FIXME error handling
return result?.error?.message || 'Failed to save'
return result?.error || new Error('Failed to save')
}
} else {
return 'Failed to save'
return new Error('Failed to save')
}
}

Expand Down
3 changes: 2 additions & 1 deletion ee/tabby-ui/components/chat/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ import {
} from '@/lib/gql/generates/graphql'
import { useDebounceCallback } from '@/lib/hooks/use-debounce'
import { useLatest } from '@/lib/hooks/use-latest'
import { ExtendedCombinedError, useThreadRun } from '@/lib/hooks/use-thread-run'
import { useThreadRun } from '@/lib/hooks/use-thread-run'
import { filename2prism } from '@/lib/language-utils'
import { ExtendedCombinedError } from '@/lib/types'
import {
AssistantMessage,
MessageActionType,
Expand Down
8 changes: 1 addition & 7 deletions ee/tabby-ui/lib/hooks/use-thread-run.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import React from 'react'
import { GraphQLError } from 'graphql'
import { CombinedError } from 'urql'

import { graphql } from '@/lib/gql/generates'

Expand All @@ -12,13 +10,9 @@ import {
ThreadRunOptionsInput
} from '../gql/generates/graphql'
import { client, useMutation } from '../tabby/gql'
import { ExtendedCombinedError } from '../types'
import { useLatest } from './use-latest'

export interface ExtendedCombinedError
extends Omit<CombinedError, 'graphQLErrors'> {
graphQLErrors?: GraphQLError[]
}

interface UseThreadRunOptions {
onError?: (err: Error) => void
threadId?: string
Expand Down
7 changes: 5 additions & 2 deletions ee/tabby-ui/lib/tabby/gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
SourceIdAccessPoliciesQueryVariables,
UpsertUserGroupMembershipInput
} from '../gql/generates/graphql'
import { ExtendedCombinedError } from '../types'
import { refreshTokenMutation } from './auth'
import {
listIntegrations,
Expand Down Expand Up @@ -88,8 +89,10 @@ function useMutation<TResult, TVariables extends AnyVariables>(
return fn
}

function makeFormErrorHandler<T extends FieldValues>(form: UseFormReturn<T>) {
return (err: CombinedError) => {
export function makeFormErrorHandler<T extends FieldValues>(
form: UseFormReturn<T>
) {
return (err: ExtendedCombinedError) => {
const { graphQLErrors = [] } = err
for (const error of graphQLErrors) {
if (error.extensions && error.extensions['validation-errors']) {
Expand Down
8 changes: 8 additions & 0 deletions ee/tabby-ui/lib/types/common.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { GraphQLError } from 'graphql'
import { CombinedError } from 'urql'

export type ServerActionResult<Result> = Promise<
| Result
| {
Expand All @@ -7,3 +10,8 @@ export type ServerActionResult<Result> = Promise<

// get element type from array type
export type ArrayElementType<T> = T extends Array<infer T> ? T : never

export interface ExtendedCombinedError
extends Omit<CombinedError, 'graphQLErrors'> {
graphQLErrors?: GraphQLError[]
}

0 comments on commit a7f65b5

Please sign in to comment.