diff --git a/src/frontend_react/public/favicon-16x16.png b/src/frontend_react/public/favicon-16x16.png deleted file mode 100644 index 9cc665537..000000000 Binary files a/src/frontend_react/public/favicon-16x16.png and /dev/null differ diff --git a/src/frontend_react/public/favicon-32x32.png b/src/frontend_react/public/favicon-32x32.png deleted file mode 100644 index f7effc777..000000000 Binary files a/src/frontend_react/public/favicon-32x32.png and /dev/null differ diff --git a/src/frontend_react/public/favicon-96x96.png b/src/frontend_react/public/favicon-96x96.png new file mode 100644 index 000000000..da387aacf Binary files /dev/null and b/src/frontend_react/public/favicon-96x96.png differ diff --git a/src/frontend_react/public/favicon.ico b/src/frontend_react/public/favicon.ico index 9cc665537..a42bfb576 100644 Binary files a/src/frontend_react/public/favicon.ico and b/src/frontend_react/public/favicon.ico differ diff --git a/src/frontend_react/public/logo192.png b/src/frontend_react/public/logo192.png index fc44b0a37..2145e9030 100644 Binary files a/src/frontend_react/public/logo192.png and b/src/frontend_react/public/logo192.png differ diff --git a/src/frontend_react/public/logo512.png b/src/frontend_react/public/logo512.png index a4e47a654..b0d71e280 100644 Binary files a/src/frontend_react/public/logo512.png and b/src/frontend_react/public/logo512.png differ diff --git a/src/frontend_react/src/components/content/HomeInput.tsx b/src/frontend_react/src/components/content/HomeInput.tsx index e45150e36..1bdd5a64f 100644 --- a/src/frontend_react/src/components/content/HomeInput.tsx +++ b/src/frontend_react/src/components/content/HomeInput.tsx @@ -1,152 +1,154 @@ import { - Body1, - Body1Strong, - Button, - Caption1, - Card, - Title2, + Body1Strong, + Button, + Caption1, + Title2, } from "@fluentui/react-components"; -import { FoodToast20Regular, Send20Regular } from "@fluentui/react-icons"; +import { Send20Regular } from "@fluentui/react-icons"; import React, { useRef, useEffect, useState } from "react"; -import { useNavigate } from "react-router-dom"; +import { useNavigate, useLocation } from "react-router-dom"; import "./../../styles/Chat.css"; import "../../styles/prism-material-oceanic.css"; import "./../../styles/HomeInput.css"; + import { HomeInputProps, quickTasks, QuickTask } from "../../models/homeInput"; import { TaskService } from "../../services/TaskService"; import { NewTaskService } from "../../services/NewTaskService"; + import ChatInput from "@/coral/modules/ChatInput"; import InlineToaster, { useInlineToaster } from "../toast/InlineToaster"; import PromptCard from "@/coral/components/PromptCard"; +import { Send } from "@/coral/imports/bundleicons"; const HomeInput: React.FC = ({ - onInputSubmit, - onQuickTaskSelect, + onInputSubmit, + onQuickTaskSelect, }) => { - const [submitting, setSubmitting] = useState(false); - const [input, setInput] = useState(""); - const textareaRef = useRef(null); - const navigate = useNavigate(); - const { showToast, dismissToast } = useInlineToaster(); - - const resetTextarea = () => { + const [submitting, setSubmitting] = useState(false); + const [input, setInput] = useState(""); + + const textareaRef = useRef(null); + const navigate = useNavigate(); + const location = useLocation(); // ✅ location.state used to control focus + const { showToast, dismissToast } = useInlineToaster(); + + useEffect(() => { + if (location.state?.focusInput) { + textareaRef.current?.focus(); + } + }, [location]); + + const resetTextarea = () => { + setInput(""); + if (textareaRef.current) { + textareaRef.current.style.height = "auto"; + textareaRef.current.focus(); + } + }; + + useEffect(() => { + const cleanup = NewTaskService.addResetListener(resetTextarea); + return cleanup; + }, []); + + const handleSubmit = async () => { + if (input.trim()) { + setSubmitting(true); + let id = showToast("Creating a plan", "progress"); + + try { + const response = await TaskService.submitInputTask(input.trim()); setInput(""); - if (textareaRef.current) { - textareaRef.current.style.height = "auto"; - textareaRef.current.focus(); - } - }; - - useEffect(() => { - const cleanup = NewTaskService.addResetListener(resetTextarea); - return cleanup; - }, []); - - const handleSubmit = async () => { - if (input.trim()) { - setSubmitting(true); - let id = showToast("Creating a plan", "progress"); - try { - const response = await TaskService.submitInputTask(input.trim()); - - setInput(""); - if (textareaRef.current) { - textareaRef.current.style.height = "auto"; - } - - - console.log('Task response', response); - if (response.plan_id && response.plan_id !== null) { - // plan_id is valid (not null or undefined) - showToast("Plan created!", "success"); - dismissToast(id); - navigate(`/plan/${response.plan_id}`); - } else { - // plan_id is not valid, handle accordingly - console.log('Invalid plan:', response.status); - - showToast("Failed to create plan", "error"); - dismissToast(id); - } - } catch (error) { - console.error("Failed to create plan:", error); - dismissToast(id); - showToast("Something went wrong", "error"); - } finally { - setInput(""); - setSubmitting(false); - } - } - }; - const handleQuickTaskClick = (task: QuickTask) => { - setInput(task.description); if (textareaRef.current) { - textareaRef.current.focus(); + textareaRef.current.style.height = "auto"; } - onQuickTaskSelect(task.description); - }; - useEffect(() => { - if (textareaRef.current) { - textareaRef.current.style.height = "auto"; - textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`; + if (response.plan_id && response.plan_id !== null) { + showToast("Plan created!", "success"); + dismissToast(id); + navigate(`/plan/${response.plan_id}`); + } else { + console.log("Invalid plan:", response.status); + showToast("Failed to create plan", "error"); + dismissToast(id); } - }, [input]); - - - - return ( -
-
-
-
- How can I help? -
- - -
+ } catch (error) { + console.error("Failed to create plan:", error); + dismissToast(id); + showToast("Something went wrong", "error"); + } finally { + setInput(""); + setSubmitting(false); + } + } + }; + + const handleQuickTaskClick = (task: QuickTask) => { + setInput(task.description); + if (textareaRef.current) { + textareaRef.current.focus(); + } + onQuickTaskSelect(task.description); + }; + + useEffect(() => { + if (textareaRef.current) { + textareaRef.current.style.height = "auto"; + textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`; + } + }, [input]); + + return ( +
+
+
+
+ How can I help? +
+ + +
- ); +
+
+ ); }; export default HomeInput; - diff --git a/src/frontend_react/src/components/content/PlanPanelLeft.tsx b/src/frontend_react/src/components/content/PlanPanelLeft.tsx index 6ce0b87e2..3beb59f1a 100644 --- a/src/frontend_react/src/components/content/PlanPanelLeft.tsx +++ b/src/frontend_react/src/components/content/PlanPanelLeft.tsx @@ -29,10 +29,7 @@ import PanelFooter from "@/coral/components/Panels/PanelFooter"; import PanelUserCard from "../../coral/components/Panels/UserCard"; import { getUserInfoGlobal } from "@/api/config"; -const PlanPanelLeft: React.FC = ({ - reloadTasks, - onNewTaskButton, -}) => { +const PlanPanelLeft: React.FC = ({ reloadTasks }) => { const { dispatchToast } = useToastController("toast"); const navigate = useNavigate(); const { planId } = useParams<{ planId: string }>(); @@ -118,14 +115,22 @@ const PlanPanelLeft: React.FC = ({
-
-
+
navigate("/", { state: { focusInput: true } })} + tabIndex={0} // ✅ allows tab focus + role="button" // ✅ announces as button + onKeyDown={(e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + navigate("/", { state: { focusInput: true } }); + } + }} + > +
-
New task -

@@ -139,7 +144,7 @@ const PlanPanelLeft: React.FC = ({ diff --git a/src/frontend_react/src/components/content/TaskDetails.tsx b/src/frontend_react/src/components/content/TaskDetails.tsx index b7ec448a8..5333e8735 100644 --- a/src/frontend_react/src/components/content/TaskDetails.tsx +++ b/src/frontend_react/src/components/content/TaskDetails.tsx @@ -154,10 +154,11 @@ const TaskDetails: React.FC = ({
{description}{" "} {functionOrDetails && ( @@ -167,10 +168,8 @@ const TaskDetails: React.FC = ({
{step.human_approval_status !== "accepted" && step.human_approval_status !== "rejected" && ( -
- + <>
+ + )}
diff --git a/src/frontend_react/src/components/content/TaskList.tsx b/src/frontend_react/src/components/content/TaskList.tsx index 0e1ef37b0..06751a47c 100644 --- a/src/frontend_react/src/components/content/TaskList.tsx +++ b/src/frontend_react/src/components/content/TaskList.tsx @@ -27,11 +27,20 @@ const TaskList: React.FC = ({ const isActive = task.id === selectedTaskId; return ( -
onTaskSelect(task.id)} - > +
onTaskSelect(task.id)} + onKeyDown={(e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + onTaskSelect(task.id); + } + }} +> +
@@ -85,7 +94,7 @@ const TaskList: React.FC = ({ - + Completed diff --git a/src/frontend_react/src/coral/components/Progress/ProgressCircle.tsx b/src/frontend_react/src/coral/components/Progress/ProgressCircle.tsx index eeff5325b..fce6306bc 100644 --- a/src/frontend_react/src/coral/components/Progress/ProgressCircle.tsx +++ b/src/frontend_react/src/coral/components/Progress/ProgressCircle.tsx @@ -12,7 +12,7 @@ const ProgressCircle: React.FC = ({ progress, size = 56, strokeWidth = 8, - backgroundColor = "var(--colorNeutralBackground1)", + backgroundColor = "var(--colorNeutralBackground6)", fillColor = "var(--colorPaletteSeafoamBorderActive)", }) => { const circleRef = useRef(null); diff --git a/src/frontend_react/src/coral/modules/ChatInput.tsx b/src/frontend_react/src/coral/modules/ChatInput.tsx index 23d221d91..98c1a476c 100644 --- a/src/frontend_react/src/coral/modules/ChatInput.tsx +++ b/src/frontend_react/src/coral/modules/ChatInput.tsx @@ -1,4 +1,10 @@ -import React, { useRef, useState, useEffect } from "react"; +import React, { + useRef, + useState, + useEffect, + forwardRef, + useImperativeHandle, +} from "react"; import { Tag, Tooltip as FluentTooltip, @@ -6,6 +12,7 @@ import { } from "@fluentui/react-components"; import HeaderTools from "../components/Header/HeaderTools"; +// ✅ Props definition interface ChatInputProps { value: string; onChange: (val: string) => void; @@ -15,141 +22,142 @@ interface ChatInputProps { disabledChat?: boolean; } -const ChatInput: React.FC = ({ - value, - onChange, - onEnter, - placeholder = "Type a message...", - children, - disabledChat, -}) => { - const [isFocused, setIsFocused] = useState(false); - const textareaRef = useRef(null); - const inputContainerRef = useRef(null); +// ✅ ForwardRef component +const ChatInput = forwardRef( + ( + { + value, + onChange, + onEnter, + placeholder = "Type a message...", + children, + disabledChat, + }, + ref + ) => { + const [isFocused, setIsFocused] = useState(false); + const textareaRef = useRef(null); + const inputContainerRef = useRef(null); - useEffect(() => { - if (textareaRef.current) { - textareaRef.current.style.height = "auto"; - textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`; - } - }, [value]); + // ✅ Allow parent to access textarea DOM node + useImperativeHandle(ref, () => textareaRef.current as HTMLTextAreaElement); - return ( -
{ + if (textareaRef.current) { + textareaRef.current.style.height = "auto"; + textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`; + } + }, [value]); - margin: "0 auto", - }} - > -
-