From b1770a5ef03d4819cfadf472564291907fb90bd5 Mon Sep 17 00:00:00 2001
From: Carter Temm <cartertemm@gmail.com>
Date: Wed, 3 Apr 2024 13:11:40 -0700
Subject: [PATCH] [BUG]: Many controls lack screen reader labels (#1023)

* Add accessible labels for back and continue buttons in onboarding flow

* Add accessible label to stop generating button

* Accessible labels for chat history actions (thumb up/down and copy)

* Accessible labels for social links in footer

* Accessible labels for home and settings links

* * Accessible labels for home, show sidebar (mobile), and workspace and thread lists.

* Implemented ARIA markup to programmatically indicate current selection and group/list association.
---
 frontend/src/components/Footer/index.jsx                   | 3 +++
 frontend/src/components/SettingsButton/index.jsx           | 2 ++
 .../ActiveWorkspaces/ThreadContainer/ThreadItem/index.jsx  | 7 ++++++-
 .../Sidebar/ActiveWorkspaces/ThreadContainer/index.jsx     | 2 +-
 frontend/src/components/Sidebar/ActiveWorkspaces/index.jsx | 7 +++++--
 frontend/src/components/Sidebar/index.jsx                  | 2 ++
 .../ChatHistory/HistoricalMessage/Actions/index.jsx        | 2 ++
 .../PromptInput/StopGenerationButton/index.jsx             | 1 +
 frontend/src/pages/OnboardingFlow/Steps/index.jsx          | 2 ++
 9 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/frontend/src/components/Footer/index.jsx b/frontend/src/components/Footer/index.jsx
index fc51dde71..10cd80cd5 100644
--- a/frontend/src/components/Footer/index.jsx
+++ b/frontend/src/components/Footer/index.jsx
@@ -52,6 +52,7 @@ export default function Footer() {
             target="_blank"
             rel="noreferrer"
             className="transition-all duration-300 p-2 rounded-full text-white bg-sidebar-button hover:bg-menu-item-selected-gradient hover:border-slate-100 hover:border-opacity-50 border-transparent border"
+            aria-label="Find us on Github"
           >
             <GithubLogo weight="fill" className="h-5 w-5 " />
           </a>
@@ -60,6 +61,7 @@ export default function Footer() {
             target="_blank"
             rel="noreferrer"
             className="transition-all duration-300 p-2 rounded-full text-white bg-sidebar-button hover:bg-menu-item-selected-gradient hover:border-slate-100 hover:border-opacity-50 border-transparent border"
+            aria-label="Docs"
           >
             <BookOpen weight="fill" className="h-5 w-5 " />
           </a>
@@ -68,6 +70,7 @@ export default function Footer() {
             target="_blank"
             rel="noreferrer"
             className="transition-all duration-300 p-2 rounded-full text-white bg-sidebar-button hover:bg-menu-item-selected-gradient hover:border-slate-100 hover:border-opacity-50 border-transparent border"
+            aria-label="Join our Discord server"
           >
             <DiscordLogo
               weight="fill"
diff --git a/frontend/src/components/SettingsButton/index.jsx b/frontend/src/components/SettingsButton/index.jsx
index 0903862db..ac2d22cdd 100644
--- a/frontend/src/components/SettingsButton/index.jsx
+++ b/frontend/src/components/SettingsButton/index.jsx
@@ -15,6 +15,7 @@ export default function SettingsButton() {
       <Link
         to={paths.home()}
         className="transition-all duration-300 p-2 rounded-full text-white bg-sidebar-button hover:bg-menu-item-selected-gradient hover:border-slate-100 hover:border-opacity-50 border-transparent border"
+        aria-label="Home"
       >
         <ArrowUUpLeft className="h-5 w-5" weight="fill" />
       </Link>
@@ -24,6 +25,7 @@ export default function SettingsButton() {
     <Link
       to={!!user?.role ? paths.settings.system() : paths.settings.appearance()}
       className="transition-all duration-300 p-2 rounded-full text-white bg-sidebar-button hover:bg-menu-item-selected-gradient hover:border-slate-100 hover:border-opacity-50 border-transparent border"
+      aria-label="Settings"
     >
       <Wrench className="h-5 w-5" weight="fill" />
     </Link>
diff --git a/frontend/src/components/Sidebar/ActiveWorkspaces/ThreadContainer/ThreadItem/index.jsx b/frontend/src/components/Sidebar/ActiveWorkspaces/ThreadContainer/ThreadItem/index.jsx
index cea32dda4..e31f4793b 100644
--- a/frontend/src/components/Sidebar/ActiveWorkspaces/ThreadContainer/ThreadItem/index.jsx
+++ b/frontend/src/components/Sidebar/ActiveWorkspaces/ThreadContainer/ThreadItem/index.jsx
@@ -25,7 +25,10 @@ export default function ThreadItem({
     : paths.workspace.thread(slug, thread.slug);
 
   return (
-    <div className="w-full relative flex h-[38px] items-center border-none hover:bg-slate-600/20 rounded-lg">
+    <div
+      className="w-full relative flex h-[38px] items-center border-none hover:bg-slate-600/20 rounded-lg"
+      role="listitem"
+    >
       {/* Curved line Element and leader if required */}
       <div
         style={{ width: THREAD_CALLOUT_DETAIL_WIDTH / 2 }}
@@ -63,6 +66,7 @@ export default function ThreadItem({
           <a
             href={window.location.pathname === linkTo ? "#" : linkTo}
             className="w-full"
+            aria-current={isActive ? "page" : ""}
           >
             <p
               className={`text-left text-sm ${
@@ -79,6 +83,7 @@ export default function ThreadItem({
               <button
                 type="button"
                 onClick={() => setShowOptions(!showOptions)}
+                aria-label="Thread options"
               >
                 <DotsThree className="text-slate-300" size={25} />
               </button>
diff --git a/frontend/src/components/Sidebar/ActiveWorkspaces/ThreadContainer/index.jsx b/frontend/src/components/Sidebar/ActiveWorkspaces/ThreadContainer/index.jsx
index 50205ef9e..d3659e3f0 100644
--- a/frontend/src/components/Sidebar/ActiveWorkspaces/ThreadContainer/index.jsx
+++ b/frontend/src/components/Sidebar/ActiveWorkspaces/ThreadContainer/index.jsx
@@ -46,7 +46,7 @@ export default function ThreadContainer({ workspace }) {
     ? threads.findIndex((thread) => thread?.slug === threadSlug) + 1
     : 0;
   return (
-    <div className="flex flex-col">
+    <div className="flex flex-col" role="list" aria-label="Threads">
       <ThreadItem
         idx={0}
         activeIdx={activeThreadIdx}
diff --git a/frontend/src/components/Sidebar/ActiveWorkspaces/index.jsx b/frontend/src/components/Sidebar/ActiveWorkspaces/index.jsx
index 7ee1c38d5..e379fd0b1 100644
--- a/frontend/src/components/Sidebar/ActiveWorkspaces/index.jsx
+++ b/frontend/src/components/Sidebar/ActiveWorkspaces/index.jsx
@@ -72,7 +72,7 @@ export default function ActiveWorkspaces() {
   }
 
   return (
-    <>
+    <div role="list" aria-label="Workspaces">
       {workspaces.map((workspace) => {
         const isActive = workspace.slug === slug;
         const isHovered = hoverStates[workspace.id];
@@ -82,6 +82,7 @@ export default function ActiveWorkspaces() {
             onMouseEnter={() => handleMouseEnter(workspace.id)}
             onMouseLeave={() => handleMouseLeave(workspace.id)}
             key={workspace.id}
+            role="listitem"
           >
             <div
               key={workspace.id}
@@ -89,6 +90,7 @@ export default function ActiveWorkspaces() {
             >
               <a
                 href={isActive ? null : paths.workspace.chat(workspace.slug)}
+                aria-current={isActive ? "page" : ""}
                 className={`
               transition-all duration-[200ms]
                 flex flex-grow w-[75%] gap-x-2 py-[6px] px-[12px] rounded-[4px] text-white justify-start items-center
@@ -154,6 +156,7 @@ export default function ActiveWorkspaces() {
                         onMouseEnter={() => handleGearMouseEnter(workspace.id)}
                         onMouseLeave={() => handleGearMouseLeave(workspace.id)}
                         className="rounded-md flex items-center justify-center text-[#A7A8A9] hover:text-white ml-auto"
+                        aria-label="General appearance settings"
                       >
                         <div className="flex hover:bg-[#646768] p-[2px] rounded-[4px]">
                           <GearSix
@@ -186,6 +189,6 @@ export default function ActiveWorkspaces() {
           providedSlug={selectedWs ? selectedWs.slug : null}
         />
       )}
-    </>
+    </div>
   );
 }
diff --git a/frontend/src/components/Sidebar/index.jsx b/frontend/src/components/Sidebar/index.jsx
index 561f46b3e..92bbbba6b 100644
--- a/frontend/src/components/Sidebar/index.jsx
+++ b/frontend/src/components/Sidebar/index.jsx
@@ -27,6 +27,7 @@ export default function Sidebar() {
       <Link
         to={paths.home()}
         className="flex shrink-0 max-w-[55%] items-center justify-start mx-[38px] my-[18px]"
+        aria-label="Home"
       >
         <img
           src={logo}
@@ -104,6 +105,7 @@ export function SidebarMobileHeader() {
           className="rounded-md p-2 flex items-center justify-center text-slate-200"
         >
           <List className="h-6 w-6" />
+          aria-label="Show sidebar"
         </button>
         <div className="flex items-center justify-center flex-grow">
           <img
diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx
index b68bc92b0..23914963f 100644
--- a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx
+++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx
@@ -58,6 +58,7 @@ function FeedbackButton({
         data-tooltip-id={tooltipId}
         data-tooltip-content={tooltipContent}
         className="text-zinc-300"
+        aria-label={tooltipContent}
       >
         <IconComponent
           size={18}
@@ -86,6 +87,7 @@ function CopyMessage({ message }) {
           data-tooltip-id="copy-assistant-text"
           data-tooltip-content="Copy"
           className="text-zinc-300"
+          aria-label="Copy"
         >
           {copied ? (
             <Check size={18} className="mb-1" />
diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/StopGenerationButton/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/StopGenerationButton/index.jsx
index 09a7c2ceb..f9872a0d8 100644
--- a/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/StopGenerationButton/index.jsx
+++ b/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/StopGenerationButton/index.jsx
@@ -14,6 +14,7 @@ export default function StopGenerationButton() {
         data-tooltip-id="stop-generation-button"
         data-tooltip-content="Stop generating response"
         className="border-none text-white/60 cursor-pointer group"
+        aria-label="Stop generating"
       >
         <svg
           width="28"
diff --git a/frontend/src/pages/OnboardingFlow/Steps/index.jsx b/frontend/src/pages/OnboardingFlow/Steps/index.jsx
index 957d94a4a..d123d8434 100644
--- a/frontend/src/pages/OnboardingFlow/Steps/index.jsx
+++ b/frontend/src/pages/OnboardingFlow/Steps/index.jsx
@@ -100,6 +100,7 @@ export function OnboardingLayout({ children }) {
             disabled={backBtn.disabled}
             onClick={backBtn.onClick}
             className="group p-2 rounded-lg border-2 border-zinc-300 disabled:border-zinc-600 h-fit w-fit disabled:not-allowed hover:bg-zinc-100 disabled:hover:bg-transparent"
+            aria-label="Back"
           >
             <ArrowLeft
               className="text-white group-hover:text-black group-disabled:text-gray-500"
@@ -127,6 +128,7 @@ export function OnboardingLayout({ children }) {
             disabled={forwardBtn.disabled}
             onClick={forwardBtn.onClick}
             className="group p-2 rounded-lg border-2 border-zinc-300 disabled:border-zinc-600 h-fit w-fit disabled:not-allowed hover:bg-zinc-100 disabled:hover:bg-transparent"
+            aria-label="Continue"
           >
             <ArrowRight
               className="text-white group-hover:text-black group-disabled:text-gray-500"
-- 
GitLab