Merge branch 'staging' into devin/1755828439-report-editor-streaming-loading

This commit is contained in:
Nate Kelley 2025-08-21 22:07:04 -06:00
commit ad92215018
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
6 changed files with 32 additions and 33 deletions

View File

@ -12,7 +12,7 @@ const editorVariants = cva(
cn(
'group/editor',
'relative w-full cursor-text overflow-x-visible break-words whitespace-pre-wrap select-text',
'rounded-md ring-offset-background focus-visible:outline-none',
'ring-offset-background focus-visible:outline-none',
'placeholder:text-muted-foreground/80 **:data-slate-placeholder:!top-1/2 **:data-slate-placeholder:-translate-y-1/2 **:data-slate-placeholder:text-muted-foreground/80 **:data-slate-placeholder:opacity-100!',
'[&_strong]:font-bold'
),
@ -21,16 +21,16 @@ const editorVariants = cva(
variant: 'default'
},
variants: {
disabled: {
true: 'cursor-not-allowed opacity-50'
readOnly: {
true: ''
},
focused: {
true: 'ring-2 ring-ring ring-offset-2'
},
variant: {
comment: cn('rounded-none border-none bg-transparent text-sm'),
default: 'size-full px-16 pt-4 pb-72 text-base sm:px-[max(64px,calc(50%-350px))]',
fullWidth: 'size-full px-16 pt-4 pb-72 text-base sm:px-24',
default: 'px-16 pt-4 pb-72 text-base sm:px-[max(64px,calc(50%-350px))]',
fullWidth: 'px-16 pt-4 pb-72 text-base sm:px-24',
none: ''
}
}
@ -40,20 +40,20 @@ const editorVariants = cva(
export type EditorProps = PlateContentProps & VariantProps<typeof editorVariants>;
export const Editor = React.forwardRef<HTMLDivElement, EditorProps>(
({ className, disabled, focused, variant, children, ...props }, ref) => {
({ className, disabled, focused, variant, readOnly, ...props }, ref) => {
return (
<PlateContent
ref={ref}
className={cn(
editorVariants({
disabled,
readOnly,
focused,
variant
}),
className
)}
disabled={disabled}
disableDefaultStyles
readOnly={readOnly}
disableDefaultStyles={true}
{...props}
/>
);

View File

@ -5,8 +5,7 @@ import { cva, type VariantProps } from 'class-variance-authority';
interface EditorContainerProps {
className?: string;
variant?: 'default' | 'comment';
readonly?: boolean;
disabled?: boolean;
readOnly?: boolean;
}
const editorContainerVariants = cva(
@ -27,13 +26,13 @@ const editorContainerVariants = cva(
'has-data-readonly:w-fit has-data-readonly:cursor-default has-data-readonly:border-transparent has-data-readonly:focus-within:[box-shadow:none]'
)
},
readonly: {
true: 'cursor-text'
readOnly: {
true: 'cursor-default user-select-none '
}
},
defaultVariants: {
variant: 'default',
readonly: false
readOnly: false
}
}
);
@ -41,8 +40,7 @@ const editorContainerVariants = cva(
export function EditorContainer({
className,
variant,
disabled,
readonly,
readOnly,
...props
}: React.ComponentProps<'div'> &
VariantProps<typeof editorContainerVariants> &
@ -51,7 +49,7 @@ export function EditorContainer({
<PlateContainer
className={cn(
'ignore-click-outside/toolbar',
editorContainerVariants({ variant, readonly }),
editorContainerVariants({ variant, readOnly }),
className
)}
{...props}

View File

@ -23,7 +23,6 @@ interface ReportEditorProps {
variant?: 'default';
className?: string;
containerClassName?: string;
disabled?: boolean;
style?: React.CSSProperties;
onValueChange?: (value: string) => void; //markdown
useFixedToolbarKit?: boolean;
@ -59,7 +58,6 @@ export const ReportEditor = React.memo(
mode = 'default',
useFixedToolbarKit = false,
readOnly = false,
disabled = false,
isStreaming = false,
children,
postEditorChildren
@ -72,9 +70,9 @@ export const ReportEditor = React.memo(
const editor = useReportEditor({
isStreaming,
mode,
readOnly,
value,
initialElements,
disabled,
useFixedToolbarKit
});
@ -123,22 +121,18 @@ export const ReportEditor = React.memo(
if (!editor) return null;
return (
<Plate
editor={editor}
readOnly={readOnly || isStreaming}
onValueChange={onValueChangeDebounced}>
<Plate editor={editor} onValueChange={onValueChangeDebounced}>
<EditorContainer
variant={variant}
readonly={readOnly}
disabled={disabled}
readOnly={readOnly}
className={cn('editor-container relative overflow-auto', containerClassName)}>
{children}
<ThemeWrapper id={id}>
<Editor
style={style}
placeholder={placeholder}
disabled={disabled}
className={cn('editor', className)}
readOnly={readOnly || isStreaming}
autoFocus
/>
</ThemeWrapper>

View File

@ -13,15 +13,15 @@ import type { ReportElementWithId } from '@buster/server-shared/reports';
export const useReportEditor = ({
value,
disabled,
isStreaming,
mode = 'default',
readOnly,
useFixedToolbarKit = false,
initialElements
}: {
value: string | undefined; //markdown
initialElements?: Value | ReportElementWithId[];
disabled: boolean;
readOnly: boolean | undefined;
useFixedToolbarKit?: boolean;
isStreaming: boolean;
mode?: 'export' | 'default';
@ -43,7 +43,7 @@ export const useReportEditor = ({
const editor = usePlateEditor({
plugins,
value: initialElements,
readOnly: disabled || isStreaming
readOnly: readOnly //this is for the initial value
});
useEditorServerUpdates({ editor, value, isStreaming });

View File

@ -12,6 +12,7 @@ import { useChatIndividualContextSelector } from '@/layouts/ChatLayout/ChatConte
import { useTrackAndUpdateReportChanges } from '@/api/buster-electric/reports/hooks';
import { ShimmerText } from '@/components/ui/typography/ShimmerText';
import { GeneratingContent } from './GeneratingContent';
import { useHotkeys } from 'react-hotkeys-hook';
export const ReportPageController: React.FC<{
reportId: string;
@ -63,7 +64,6 @@ export const ReportPageController: React.FC<{
<DynamicReportEditor
value={content}
placeholder="Start typing..."
disabled={false}
className={commonClassName}
containerClassName="pt-9"
variant="default"

View File

@ -66,8 +66,15 @@ export function createModifyReportsReasoningEntry(
}
}
// Calculate elapsed time when complete
secondaryTitle = formatElapsedTime(state.startTime);
// Only show elapsed time when all edits are complete (not during streaming)
// Check if all edits have a final status (completed or failed), not just 'loading'
const allEditsComplete = state.edits?.every(
(edit) => edit.status === 'completed' || edit.status === 'failed'
) ?? false;
if (allEditsComplete) {
secondaryTitle = formatElapsedTime(state.startTime);
}
}
return {