Skip to content

Commit

Permalink
Upg: improve builder UX when using a template for instructions (#6722)
Browse files Browse the repository at this point in the history
* Upg: improve builder UX when using a template for instructions

* fix lint

* Add: comment about re-rendering cost
  • Loading branch information
Fraggle authored Aug 9, 2024
1 parent 556efd3 commit 78f7cd9
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 8 deletions.
6 changes: 6 additions & 0 deletions front/components/assistant_builder/AssistantBuilder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,10 @@ export default function AssistantBuilder({
screen,
]);

const [doTypewriterEffect, setDoTypewriterEffect] = useState(
Boolean(template !== null && builderState.instructions)
);

const modalTitle = agentConfigurationId
? `Edit @${builderState.handle}`
: "New Assistant";
Expand Down Expand Up @@ -454,6 +458,8 @@ export default function AssistantBuilder({
resetAt={instructionsResetAt}
isUsingTemplate={template !== null}
instructionsError={instructionsError}
doTypewriterEffect={doTypewriterEffect}
setDoTypewriterEffect={setDoTypewriterEffect}
/>
);
case "actions":
Expand Down
66 changes: 58 additions & 8 deletions front/components/assistant_builder/InstructionScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ export function InstructionScreen({
resetAt,
isUsingTemplate,
instructionsError,
doTypewriterEffect,
setDoTypewriterEffect,
}: {
owner: WorkspaceType;
plan: PlanType;
Expand All @@ -115,6 +117,8 @@ export function InstructionScreen({
resetAt: number | null;
isUsingTemplate: boolean;
instructionsError: string | null;
doTypewriterEffect: boolean;
setDoTypewriterEffect: (doTypewriterEffect: boolean) => void;
}) {
const editor = useEditor({
extensions: [
Expand All @@ -126,19 +130,65 @@ export function InstructionScreen({
limit: INSTRUCTIONS_MAXIMUM_CHARACTER_COUNT,
}),
],
content: tipTapContentFromPlainText(builderState.instructions || ""),
editable: !doTypewriterEffect,
content: tipTapContentFromPlainText(
(!doTypewriterEffect && builderState.instructions) || ""
),
onUpdate: ({ editor }) => {
const json = editor.getJSON();
const plainText = plainTextFromTipTapContent(json);
setEdited(true);
setBuilderState((state) => ({
...state,
instructions: plainText,
}));
if (!doTypewriterEffect) {
const json = editor.getJSON();
const plainText = plainTextFromTipTapContent(json);
setEdited(true);
setBuilderState((state) => ({
...state,
instructions: plainText,
}));
}
},
});
const editorService = useInstructionEditorService(editor);

const [letterIndex, setLetterIndex] = useState(0);

// Beware that using this useEffect will cause a lot of re-rendering until we finished the visual effect
// We must be careful to avoid any heavy rendering in this component
useEffect(() => {
if (doTypewriterEffect && editor && builderState.instructions) {
// Get the text from content and strip HTML tags for simplicity and being able to write letter by letter
const textContent = builderState.instructions.replace(/<[^>]*>?/gm, "");
const delay = 2; // Typing delay in milliseconds
if (letterIndex < textContent.length) {
const timeoutId = setTimeout(() => {
// Append next character
editor
.chain()
.focus("end")
.insertContent(textContent[letterIndex], {
updateSelection: false,
})
.run();
setLetterIndex(letterIndex + 1);
}, delay);
return () => clearTimeout(timeoutId);
} else {
// We reset the content at the end otherwise we lose all carriage returns (i'm not sure why)
editor
.chain()
.setContent(tipTapContentFromPlainText(builderState.instructions))
.focus("end")
.run();
editor.setEditable(true);
setDoTypewriterEffect(false);
}
}
}, [
editor,
letterIndex,
builderState.instructions,
doTypewriterEffect,
setDoTypewriterEffect,
]);

const currentCharacterCount = editor?.storage.characterCount.characters();

useEffect(() => {
Expand Down

0 comments on commit 78f7cd9

Please sign in to comment.