diff --git a/content/copilot/managing-copilot/configuring-and-auditing-content-exclusion/excluding-content-from-github-copilot.md b/content/copilot/managing-copilot/configuring-and-auditing-content-exclusion/excluding-content-from-github-copilot.md index c550c02d9d8b..446908d79a56 100644 --- a/content/copilot/managing-copilot/configuring-and-auditing-content-exclusion/excluding-content-from-github-copilot.md +++ b/content/copilot/managing-copilot/configuring-and-auditing-content-exclusion/excluding-content-from-github-copilot.md @@ -45,6 +45,7 @@ Repository administrators{% ifversion ghec %}, organization owners, and enterpri | JetBrains IDEs | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | | Vim/Neovim | {% octicon "check" aria-label="Supported" %} | Not applicable | | Xcode | {% octicon "check" aria-label="Supported" %} | Not applicable | +| Eclipse | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} | | Azure Data Studio | {% octicon "x" aria-label="Not supported" %} | Not applicable | | The {% data variables.product.github %} website | Not applicable | {% octicon "check" aria-label="Supported" %} | | {% data variables.product.prodname_mobile %} | Not applicable | {% octicon "check" aria-label="Supported" %} | diff --git a/src/search/components/input/AskAIResults.tsx b/src/search/components/input/AskAIResults.tsx index e63236379320..2e3cd123ae28 100644 --- a/src/search/components/input/AskAIResults.tsx +++ b/src/search/components/input/AskAIResults.tsx @@ -58,6 +58,7 @@ export function AskAIResults({ const [message, setMessage] = useState('') const [initialLoading, setInitialLoading] = useState(true) const [responseLoading, setResponseLoading] = useState(false) + const [announcement, setAnnouncement] = useState('') const disclaimerRef = useRef(null) // We cache up to 1000 queries, and expire them after 30 days const { getItem, setItem } = useAISearchLocalStorageCache<{ @@ -83,6 +84,7 @@ export function AskAIResults({ status: 400, }) setMessage(cannedResponse) + setAnnouncement(cannedResponse) setReferences([]) setItem( query, @@ -105,6 +107,7 @@ export function AskAIResults({ } let isCancelled = false setMessage('') + setAnnouncement('') setReferences([]) setAICouldNotAnswer(false) setInitialLoading(true) @@ -118,6 +121,7 @@ export function AskAIResults({ setAICouldNotAnswer(cachedData.aiCouldNotAnswer || false) setInitialLoading(false) setResponseLoading(false) + sendAISearchResultEvent({ sources: cachedData.sources, message: cachedData.message, @@ -125,6 +129,10 @@ export function AskAIResults({ couldNotAnswer: cachedData.aiCouldNotAnswer, status: cachedData.aiCouldNotAnswer ? 400 : 200, }) + + setTimeout(() => { + setAnnouncement(cachedData.message) + }, 1500) return } @@ -203,6 +211,9 @@ export function AskAIResults({ setMessage(messageBuffer) } } + if (!isCancelled) { + setAnnouncement('Copilot Response Loading...') + } } } } @@ -246,18 +257,12 @@ export function AskAIResults({ return (
- {/* Hidden status message for screen readers */} - - {initialLoading || responseLoading - ? t('search.ai.loading_status_message') - : t('search.ai.done_loading_status_message')} - {initialLoading ? (
) : ( -
+
{!aiCouldNotAnswer && message !== '' ? ( {t('search.ai.disclaimer')} @@ -358,6 +363,8 @@ export function AskAIResults({ paddingLeft: '0px', }} key={`reference-${index}`} + id={`search-option-reference-${index + referencesIndexOffset}`} + role="option" tabIndex={-1} onSelect={() => { referenceOnSelect(source.url) @@ -374,6 +381,22 @@ export function AskAIResults({ ) : null} +
+ {announcement} +
) } diff --git a/src/search/components/input/SearchOverlay.tsx b/src/search/components/input/SearchOverlay.tsx index 3d0abcec80df..d158574459c8 100644 --- a/src/search/components/input/SearchOverlay.tsx +++ b/src/search/components/input/SearchOverlay.tsx @@ -39,6 +39,7 @@ import { EventType } from '@/events/types' import { ASK_AI_EVENT_GROUP, SEARCH_OVERLAY_EVENT_GROUP } from '@/events/components/event-groups' import type { AIReference } from '../types' import type { AutocompleteSearchHit, GeneralSearchHit } from '@/search/types' +import { focusTrap } from '@primer/behaviors' type Props = { searchOverlayOpen: boolean @@ -88,6 +89,14 @@ export function SearchOverlay({ // Group all events between open / close of the overlay together const searchEventGroupId = useRef('') + const overlayRef = useRef(null) + + useEffect(() => { + if (searchOverlayOpen && overlayRef.current) { + focusTrap(overlayRef.current, inputRef.current || undefined) + } + }, [searchOverlayOpen]) + useEffect(() => { searchEventGroupId.current = uuidv4() }, [searchOverlayOpen]) @@ -486,6 +495,7 @@ export function SearchOverlay({ <>
} aria-labelledby={overlayHeadingId} + role="combobox" + aria-controls="search-suggestions-list" + aria-expanded={combinedOptions.length > 0} + aria-activedescendant={ + selectedIndex >= 0 + ? `search-option-${combinedOptions[selectedIndex].group}-${selectedIndex}` + : undefined + } + onKeyDown={handleKeyDown} placeholder={t('search.input.placeholder_no_icon')} trailingAction={ option.isViewAllResults ? performGeneralSearch() : generalSearchResultOnSelect(option) } @@ -843,11 +867,7 @@ function renderSearchGroups( groups.push( - + {t('search.overlay.general_suggestions_list_heading')} {items} @@ -872,11 +892,7 @@ function renderSearchGroups( if (aiOptionsWithUserInput.length && !isInAskAIState) { groups.push( - + {t('search.overlay.ai_autocomplete_list_heading')} @@ -887,6 +903,9 @@ function renderSearchGroups( const item = ( aiAutocompleteOnSelect(option)} active={isActive} tabIndex={-1}