mirror of
https://github.com/onyx-dot-app/onyx.git
synced 2026-10-23 11:53:08 -05:00
* multiple slackbot support * app_id + tenant_id key * removed kv store stuff * fixed up mypy and migration * got frontend working for multiple slack bots * some frontend stuff * alembic fix * might be valid * refactor dun * alembic stuff * temp frontend stuff * alembic stuff * maybe fixed alembic * maybe dis fix * im getting mad * api names changed * tested * almost done * done * routing nonsense * done! * done!! * fr done * doneski * fix alembic migration * getting mad again * PLEASE IM BEGGING YOU
112 lines
3.0 KiB
TypeScript
112 lines
3.0 KiB
TypeScript
import { usePopup } from "@/components/admin/connectors/Popup";
|
|
import { CheckmarkIcon, XIcon } from "@/components/icons/icons";
|
|
import { Button } from "@/components/ui/button";
|
|
import { useEffect, useRef, useState } from "react";
|
|
import { Textarea } from "@/components/ui/textarea";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface EditableTextAreaDisplayProps {
|
|
value: string;
|
|
isEditable: boolean;
|
|
onUpdate: (newValue: string) => Promise<void>;
|
|
textClassName?: string;
|
|
scale?: number;
|
|
}
|
|
|
|
export function EditableTextAreaDisplay({
|
|
value,
|
|
isEditable,
|
|
onUpdate,
|
|
textClassName,
|
|
scale = 1,
|
|
}: EditableTextAreaDisplayProps) {
|
|
const [isEditing, setIsEditing] = useState(false);
|
|
const [editableValue, setEditableValue] = useState(value);
|
|
const inputRef = useRef<HTMLInputElement | HTMLTextAreaElement>(null);
|
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
|
|
useEffect(() => {
|
|
if (isEditing && inputRef.current) {
|
|
inputRef.current.focus();
|
|
}
|
|
}, [isEditing]);
|
|
|
|
useEffect(() => {
|
|
const handleClickOutside = (event: MouseEvent) => {
|
|
if (
|
|
containerRef.current &&
|
|
!containerRef.current.contains(event.target as Node) &&
|
|
isEditing
|
|
) {
|
|
resetEditing();
|
|
}
|
|
};
|
|
|
|
document.addEventListener("mousedown", handleClickOutside);
|
|
return () => {
|
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
};
|
|
}, [isEditing]);
|
|
|
|
const handleValueChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
setEditableValue(e.target.value);
|
|
};
|
|
|
|
const handleUpdate = async () => {
|
|
await onUpdate(editableValue);
|
|
setIsEditing(false);
|
|
};
|
|
|
|
const resetEditing = () => {
|
|
setIsEditing(false);
|
|
setEditableValue(value);
|
|
};
|
|
|
|
const handleKeyDown = (
|
|
e: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>
|
|
) => {
|
|
if (e.key === "Enter") {
|
|
handleUpdate();
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div ref={containerRef} className={"flex items-center"}>
|
|
<Textarea
|
|
ref={inputRef as React.RefObject<HTMLTextAreaElement>}
|
|
value={editableValue}
|
|
onChange={(e) => setEditableValue(e.target.value)}
|
|
onKeyDown={handleKeyDown}
|
|
className={cn(
|
|
textClassName,
|
|
"bg-white",
|
|
isEditable && !isEditing && "cursor-pointer"
|
|
)}
|
|
style={{ fontSize: `${scale}rem` }}
|
|
readOnly={!isEditing}
|
|
onClick={() => isEditable && !isEditing && setIsEditing(true)}
|
|
/>
|
|
{isEditing && isEditable ? (
|
|
<div className={cn("flex", "flex-col gap-1")}>
|
|
<Button
|
|
onClick={handleUpdate}
|
|
variant="ghost"
|
|
size="sm"
|
|
className="p-0 hover:bg-transparent ml-2"
|
|
>
|
|
<CheckmarkIcon className={`text-600`} size={12 * scale} />
|
|
</Button>
|
|
<Button
|
|
onClick={resetEditing}
|
|
variant="ghost"
|
|
size="sm"
|
|
className="p-0 hover:bg-transparent ml-2"
|
|
>
|
|
<XIcon className={`text-600`} size={12 * scale} />
|
|
</Button>
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
);
|
|
}
|