Merge pull request #588 from lfnovo/fix/ui-fixes
fix: UI overflow, translation proxy, and notes API fixes
This commit is contained in:
commit
6226db2746
13 changed files with 23 additions and 27 deletions
|
|
@ -96,7 +96,7 @@ async def create_note(note_data: NoteCreate):
|
||||||
note_type=new_note.note_type,
|
note_type=new_note.note_type,
|
||||||
created=str(new_note.created),
|
created=str(new_note.created),
|
||||||
updated=str(new_note.updated),
|
updated=str(new_note.updated),
|
||||||
command_id=command_id,
|
command_id=str(command_id) if command_id else None,
|
||||||
)
|
)
|
||||||
except HTTPException:
|
except HTTPException:
|
||||||
raise
|
raise
|
||||||
|
|
@ -160,7 +160,7 @@ async def update_note(note_id: str, note_update: NoteUpdate):
|
||||||
note_type=note.note_type,
|
note_type=note.note_type,
|
||||||
created=str(note.created),
|
created=str(note.created),
|
||||||
updated=str(note.updated),
|
updated=str(note.updated),
|
||||||
command_id=command_id,
|
command_id=str(command_id) if command_id else None,
|
||||||
)
|
)
|
||||||
except HTTPException:
|
except HTTPException:
|
||||||
raise
|
raise
|
||||||
|
|
|
||||||
|
|
@ -230,7 +230,7 @@ export default function NotebookPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Chat Column - always expanded, takes remaining space */}
|
{/* Chat Column - always expanded, takes remaining space */}
|
||||||
<div className="transition-all duration-150 flex-1 lg:pr-6 lg:-mr-6">
|
<div className="transition-all duration-150 flex-1 min-w-0 lg:pr-6 lg:-mr-6">
|
||||||
<ChatColumn
|
<ChatColumn
|
||||||
notebookId={notebookId}
|
notebookId={notebookId}
|
||||||
contextSelections={contextSelections}
|
contextSelections={contextSelections}
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ export function NoteEditorDialog({ open, onOpenChange, notebookId, note }: NoteE
|
||||||
<DialogTitle className="sr-only">
|
<DialogTitle className="sr-only">
|
||||||
{isEditing ? t.sources.editNote : t.sources.createNote}
|
{isEditing ? t.sources.editNote : t.sources.createNote}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<form onSubmit={handleSubmit(onSubmit)} className="flex h-full flex-col">
|
<form onSubmit={handleSubmit(onSubmit)} className="flex h-full flex-col min-w-0">
|
||||||
{isEditing && noteLoading ? (
|
{isEditing && noteLoading ? (
|
||||||
<div className="flex-1 flex items-center justify-center py-10">
|
<div className="flex-1 flex items-center justify-center py-10">
|
||||||
<span className="text-sm text-muted-foreground">{t.common.loading}</span>
|
<span className="text-sm text-muted-foreground">{t.common.loading}</span>
|
||||||
|
|
|
||||||
|
|
@ -179,11 +179,11 @@ export function NotesColumn({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{note.title && (
|
{note.title && (
|
||||||
<h4 className="text-sm font-medium mb-2">{note.title}</h4>
|
<h4 className="text-sm font-medium mb-2 break-all">{note.title}</h4>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{note.content && (
|
{note.content && (
|
||||||
<p className="text-sm text-muted-foreground line-clamp-3">
|
<p className="text-sm text-muted-foreground line-clamp-3 break-all">
|
||||||
{note.content}
|
{note.content}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ export function InlineEdit({
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={cn(
|
className={cn(
|
||||||
"cursor-pointer hover:bg-muted/50 rounded px-2 py-1 -mx-2 -my-1 transition-colors text-left w-full",
|
"cursor-pointer hover:bg-muted/50 rounded px-2 py-1 -mx-2 -my-1 transition-colors text-left w-full break-all",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ export function CreateNotebookDialog({ open, onOpenChange }: CreateNotebookDialo
|
||||||
|
|
||||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
|
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="notebook-name">{t.common.name || 'Name'} *</Label>
|
<Label htmlFor="notebook-name">{t.common.name} *</Label>
|
||||||
<Input
|
<Input
|
||||||
id="notebook-name"
|
id="notebook-name"
|
||||||
{...register('name')}
|
{...register('name')}
|
||||||
|
|
|
||||||
|
|
@ -203,7 +203,7 @@ export function ChatPanel({
|
||||||
onReferenceClick={handleReferenceClick}
|
onReferenceClick={handleReferenceClick}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<p className="text-sm break-words overflow-wrap-anywhere">{message.content}</p>
|
<p className="text-sm break-all">{message.content}</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{message.type === 'ai' && (
|
{message.type === 'ai' && (
|
||||||
|
|
@ -290,7 +290,7 @@ export function ChatPanel({
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex gap-2 items-end">
|
<div className="flex gap-2 items-end min-w-0">
|
||||||
<Textarea
|
<Textarea
|
||||||
id={chatInputId}
|
id={chatInputId}
|
||||||
name="chat-message"
|
name="chat-message"
|
||||||
|
|
@ -300,7 +300,7 @@ export function ChatPanel({
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
placeholder={`${t.chat.sendPlaceholder} (${t.chat.pressToSend.replace('{key}', keyHint)})`}
|
placeholder={`${t.chat.sendPlaceholder} (${t.chat.pressToSend.replace('{key}', keyHint)})`}
|
||||||
disabled={isStreaming}
|
disabled={isStreaming}
|
||||||
className="flex-1 min-h-[40px] max-h-[100px] resize-none py-2 px-3"
|
className="flex-1 min-h-[40px] max-h-[100px] resize-none py-2 px-3 min-w-0"
|
||||||
rows={1}
|
rows={1}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
|
|
@ -542,7 +542,7 @@ export function AddSourceDialog({
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)} className="min-w-0">
|
||||||
<WizardContainer
|
<WizardContainer
|
||||||
currentStep={currentStep}
|
currentStep={currentStep}
|
||||||
steps={WIZARD_STEPS}
|
steps={WIZARD_STEPS}
|
||||||
|
|
|
||||||
|
|
@ -240,7 +240,7 @@ export function SourceCard({
|
||||||
{/* Title */}
|
{/* Title */}
|
||||||
<div className={cn('mb-1.5', !isCompleted && 'mb-1')}>
|
<div className={cn('mb-1.5', !isCompleted && 'mb-1')}>
|
||||||
<h4
|
<h4
|
||||||
className="text-sm font-medium leading-tight line-clamp-2"
|
className="text-sm font-medium leading-tight line-clamp-2 break-all"
|
||||||
title={title}
|
title={title}
|
||||||
>
|
>
|
||||||
{title}
|
{title}
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ const DialogContent = ({
|
||||||
data-slot="dialog-content"
|
data-slot="dialog-content"
|
||||||
aria-describedby={undefined}
|
aria-describedby={undefined}
|
||||||
className={cn(
|
className={cn(
|
||||||
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:pointer-events-none fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-[calc(100%-2rem)]",
|
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:pointer-events-none fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-[calc(100%-2rem)] overflow-hidden",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
|
||||||
<textarea
|
<textarea
|
||||||
data-slot="textarea"
|
data-slot="textarea"
|
||||||
className={cn(
|
className={cn(
|
||||||
"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 min-w-0 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
||||||
|
|
@ -85,15 +85,15 @@ export function WizardContainer({
|
||||||
className
|
className
|
||||||
}: WizardContainerProps) {
|
}: WizardContainerProps) {
|
||||||
return (
|
return (
|
||||||
<div className={cn('flex flex-col h-[500px] bg-card rounded-lg border border-border', className)}>
|
<div className={cn('flex flex-col h-[500px] min-w-0 overflow-hidden bg-card rounded-lg border border-border', className)}>
|
||||||
<StepIndicator
|
<StepIndicator
|
||||||
currentStep={currentStep}
|
currentStep={currentStep}
|
||||||
steps={steps}
|
steps={steps}
|
||||||
onStepClick={onStepClick}
|
onStepClick={onStepClick}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="flex-1 overflow-hidden">
|
<div className="flex-1 min-w-0 overflow-hidden">
|
||||||
<div className="h-full overflow-y-auto px-6 py-4">
|
<div className="h-full min-w-0 overflow-y-auto px-6 py-4">
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -78,12 +78,6 @@ export function useTranslation() {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
return (target as any)[prop];
|
return (target as any)[prop];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle function's own properties
|
|
||||||
if (prop in target) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
return (target as any)[prop];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof prop !== 'string') return undefined;
|
if (typeof prop !== 'string') return undefined;
|
||||||
|
|
||||||
|
|
@ -94,7 +88,9 @@ export function useTranslation() {
|
||||||
|
|
||||||
const currentPath = path ? `${path}.${prop}` : prop;
|
const currentPath = path ? `${path}.${prop}` : prop;
|
||||||
|
|
||||||
// Try to get the translation
|
// Try to get the translation first (before checking target properties,
|
||||||
|
// since target is a function and has built-in properties like 'name'
|
||||||
|
// that would shadow translation keys)
|
||||||
const result = i18nTranslateCopy(currentPath, { returnObjects: true });
|
const result = i18nTranslateCopy(currentPath, { returnObjects: true });
|
||||||
|
|
||||||
// If it's a leaf string, return it directly
|
// If it's a leaf string, return it directly
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue