Skip to content

Commit

Permalink
Merge pull request #36500 from github/repo-sync
Browse files Browse the repository at this point in the history
Repo sync
  • Loading branch information
docs-bot authored Feb 26, 2025
2 parents c0bb4c5 + 2e21b74 commit be0208b
Show file tree
Hide file tree
Showing 27 changed files with 907 additions and 468 deletions.
2 changes: 1 addition & 1 deletion content/rest/orgs/rule-suites.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ intro: Use the REST API to manage rule suites for organizations.
versions: # DO NOT MANUALLY EDIT. CHANGES WILL BE OVERWRITTEN BY A 🤖
fpt: '*'
ghec: '*'
ghes: '>=3.12'
ghes: '*'
topics:
- API
autogenerated: rest
Expand Down
2 changes: 1 addition & 1 deletion content/rest/repos/rule-suites.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ intro: Use the REST API to manage rule suites for repositories.
versions: # DO NOT MANUALLY EDIT. CHANGES WILL BE OVERWRITTEN BY A 🤖
fpt: '*'
ghec: '*'
ghes: '>=3.12'
ghes: '*'
topics:
- API
autogenerated: rest
Expand Down
8 changes: 5 additions & 3 deletions data/ui.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,22 @@ search:
beta_tag: Beta
return_to_search: Return to search
clear_search_query: Clear
view_all_search_results: View all {{length}} results
no_results_found: No results found
ai:
disclaimer: Copilot uses AI. Check for mistakes by reviewing the links in the response.
references: References from these articles
loading_status_message: Loading Copilot response...
done_loading_status_message: Done loading Copilot response
unable_to_answer: Sorry, I'm unable to answer that question. Please try a different query.
unable_to_answer: Sorry, I'm unable to answer that question. Please try a different query or search our docs.
copy_answer: Copy answer
copied_announcement: Copied!
thumbs_up: This answer was helpful
thumbs_down: This answer was not helpful
thumbs_announcement: Thank you for your feedback!
failure:
autocomplete_title: There was an error loading autocomplete results.
ai_title: There was an error loading the AI assistant.
general_title: There was an error loading search results.
ai_title: There was an error loading Copilot.
description: You can still use this field to search our docs.
old_search:
description: Enter a search term to find it in the GitHub Docs.
Expand Down
23 changes: 23 additions & 0 deletions src/events/lib/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,22 @@ const exit = {
},
}

const keyboard = {
type: 'object',
additionalProperties: false,
required: ['pressed_key', 'pressed_on'],
properties: {
pressed_key: {
type: 'string',
description: 'The key the user pressed.',
},
pressed_on: {
type: 'string',
description: 'The element/identifier the user pressed the key on.',
},
},
}

const link = {
type: 'object',
additionalProperties: false,
Expand Down Expand Up @@ -400,6 +416,7 @@ const aiSearchResult = {
'ai_search_result_query',
'ai_search_result_response',
'ai_search_result_links_json',
'ai_search_result_provided_answer',
],
properties: {
context,
Expand All @@ -420,6 +437,10 @@ const aiSearchResult = {
description:
'Dynamic JSON string of an array of "link" objects in the form: [{ "type": "reference" | "inline", "url": "https://..", "product": "issues" | "pages" | ... }, ...]',
},
ai_search_result_provided_answer: {
type: 'boolean',
description: 'Whether the GPT was able to answer the query.',
},
},
}

Expand Down Expand Up @@ -584,6 +605,7 @@ const validation = {
export const schemas = {
page,
exit,
keyboard,
link,
hover,
search,
Expand All @@ -600,6 +622,7 @@ export const schemas = {
export const hydroNames = {
page: 'docs.v0.PageEvent',
exit: 'docs.v0.ExitEvent',
keyboard: 'docs.v0.KeyboardEvent',
link: 'docs.v0.LinkEvent',
hover: 'docs.v0.HoverEvent',
search: 'docs.v0.SearchEvent',
Expand Down
6 changes: 6 additions & 0 deletions src/events/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export enum EventType {
aiSearchResult = 'aiSearchResult',
page = 'page',
exit = 'exit',
keyboard = 'keyboard',
link = 'link',
hover = 'hover',
search = 'search',
Expand Down Expand Up @@ -59,6 +60,7 @@ export type EventPropsByType = {
// Dynamic JSON string of an array of "link" objects in the form:
// [{ "type": "reference" | "inline", "url": "https://..", "product": "issues" | "pages" | ... }, ...]
ai_search_result_links_json: string
ai_search_result_provided_answer: boolean
}
[EventType.clipboard]: {
clipboard_operation: string
Expand All @@ -82,6 +84,10 @@ export type EventPropsByType = {
hover_url: string
hover_samesite?: boolean
}
[EventType.keyboard]: {
pressed_key: string
pressed_on: string
}
[EventType.link]: {
link_url: string
link_samesite?: boolean
Expand Down
8 changes: 5 additions & 3 deletions src/fixtures/fixtures/data/ui.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,22 @@ search:
beta_tag: Beta
return_to_search: Return to search
clear_search_query: Clear
view_all_search_results: View all {{length}} results
no_results_found: No results found
ai:
disclaimer: Copilot uses AI. Check for mistakes by reviewing the links in the response.
references: References from these articles
loading_status_message: Loading Copilot response...
done_loading_status_message: Done loading Copilot response
unable_to_answer: Sorry, I'm unable to answer that question. Please try a different query.
unable_to_answer: Sorry, I'm unable to answer that question. Please try a different query or search our docs.
copy_answer: Copy answer
copied_announcement: Copied!
thumbs_up: This answer was helpful
thumbs_down: This answer was not helpful
thumbs_announcement: Thank you for your feedback!
failure:
autocomplete_title: There was an error loading autocomplete results.
ai_title: There was an error loading the AI assistant.
general_title: There was an error loading search results.
ai_title: There was an error loading Copilot.
description: You can still use this field to search our docs.
old_search:
description: Enter a search term to find it in the GitHub Docs.
Expand Down
41 changes: 36 additions & 5 deletions src/fixtures/tests/playwright-rendering.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,22 +82,53 @@ test('open new search, and perform a general search', async ({ page }) => {
await page.getByTestId('search').click()

await page.getByTestId('overlay-search-input').fill('serve playwright')
// Let new suggestions load
// Wait for the results to load
// NOTE: In the UI we wait for results to load before allowing "enter", because we don't want
// to allow an unnecessary request when there are no search results. Easier to wait 1 second
await page.waitForTimeout(1000)
// Navigate to general search item, "serve playwright"
await page.keyboard.press('ArrowDown')
// Select the general search item, "serve playwright"
// Press enter to perform general search
await page.keyboard.press('Enter')

await expect(page).toHaveURL(/\/search\?query=serve\+playwright/)
await expect(page).toHaveURL(
/\/search\?search-overlay-input=serve\+playwright&query=serve\+playwright/,
)
await expect(page).toHaveTitle(/\d Search results for "serve playwright"/)

// The first result should be "For Playwright"
await page.getByRole('link', { name: 'For Playwright' }).click()

await expect(page).toHaveURL(/\/get-started\/foo\/for-playwright$/)
await expect(page).toHaveTitle(/For Playwright/)
})

test('open new search, and select a general search article', async ({ page }) => {
test.skip(!SEARCH_TESTS, 'No local Elasticsearch, no tests involving search')

await page.goto('/')

// Enable the AI search experiment by overriding the control group
await page.evaluate(() => {
// @ts-expect-error overrideControlGroup is a custom function added to the window object
window.overrideControlGroup('ai_search_experiment', 'treatment')
})

await page.getByTestId('search').click()

await page.getByTestId('overlay-search-input').fill('serve playwright')
// Let new suggestions load
await page.waitForTimeout(1000)
// Navigate to general search item, "For Playwright"
await page.keyboard.press('ArrowDown')
// Select the general search item, "For Playwright"
await page.keyboard.press('Enter')

// We should now be on the page for "For Playwright"
await expect(page).toHaveURL(
/\/get-started\/foo\/for-playwright\?search-overlay-input=serve\+playwright$/,
)
await expect(page).toHaveTitle(/For Playwright/)
})

test('open new search, and get auto-complete results', async ({ page }) => {
test.skip(!SEARCH_TESTS, 'No local Elasticsearch, no tests involving search')

Expand Down
73 changes: 26 additions & 47 deletions src/frame/components/hooks/useQueryParam.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// The `queryParam` variable returned from this method are stateful and will be set to the query param on page load

import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { useState, useEffect } from 'react'
import { parseDebug } from '@/search/components/hooks/useQuery'

type UseQueryParamReturn<T extends string | boolean> = {
Expand All @@ -23,69 +23,48 @@ export function useQueryParam(
): UseQueryParamReturn<any> {
const router = useRouter()

// Determine the initial value of the query param
let initialQueryParam = ''
const paramValue = router.query[queryParamKey]

if (paramValue) {
if (Array.isArray(paramValue)) {
initialQueryParam = paramValue[0]
} else {
initialQueryParam = paramValue
}
}

const debugValue = parseDebug(router.query.debug)

// Return type will be set based on overloads
const [queryParamString, setQueryParamState] = useState<string>(initialQueryParam)
const [debug] = useState<boolean>(debugValue)
const [queryParamString, setQueryParamState] = useState<string>('')
const [debug, setDebug] = useState<boolean>(false)
const queryParam: string | boolean = isBoolean ? queryParamString === 'true' : queryParamString

// If the query param changes in the URL, update the state
// Only set the initial query param values on page load, the rest of the time we use React state
useEffect(() => {
let initialQueryParam = ''
const paramValue = router.query[queryParamKey]

if (paramValue) {
if (Array.isArray(paramValue)) {
setQueryParamState(paramValue[0])
} else {
setQueryParamState(paramValue)
}
initialQueryParam = Array.isArray(paramValue) ? paramValue[0] : paramValue
}
}, [router.query, queryParamKey])

// Determine the type of queryParam based on isBoolean
const queryParam: string | boolean = isBoolean ? queryParamString === 'true' : queryParamString
setQueryParamState(initialQueryParam)
setDebug(parseDebug(router.query.debug || '') || false)
}, [queryParamKey, router.pathname])

const setQueryParam = (value: string | boolean) => {
const { pathname, hash, search } = window.location

let newValue: string = value as string

// If it's a false boolean or empty string, just remove the query param
if (!value) {
newValue = ''
} else if (typeof value === 'boolean') {
newValue = 'true'
}

const params = new URLSearchParams(search)
const newValue = typeof value === 'boolean' ? (value ? 'true' : '') : value
const [asPathWithoutHash] = router.asPath.split('#')
const [asPathRoot, asPathQuery = ''] = asPathWithoutHash.split('?')
const currentParams = new URLSearchParams(asPathQuery)
if (newValue) {
params.set(queryParamKey, newValue)
currentParams.set(queryParamKey, newValue)
} else {
params.delete(queryParamKey)
currentParams.delete(queryParamKey)
}
const paramsString = currentParams.toString() ? `?${currentParams.toString()}` : ''
let newUrl = `${asPathRoot}${paramsString}`
if (asPathRoot !== '/' && router.locale) {
newUrl = `${router.locale}${asPathRoot}${paramsString}`
}
if (!newUrl.startsWith('/')) {
newUrl = `/${newUrl}`
}

const newSearch = params.toString()
const newUrl = newSearch ? `${pathname}?${newSearch}${hash}` : `${pathname}${hash}`
router.replace(newUrl, undefined, { shallow: true, locale: router.locale, scroll: false })

window.history.replaceState({}, '', newUrl)
setQueryParamState(newValue)
}

return {
debug,
queryParam: queryParam as any, // Type will be set based on overloads
setQueryParam: setQueryParam as any,
setQueryParam,
}
}
12 changes: 12 additions & 0 deletions src/frame/components/page-header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,18 @@ export const Header = () => {
return () => window.removeEventListener('keydown', close)
}, [])

// Listen for '/' so we can open the search overlay when pressed. (only enabled for showNewSearch is true for new search experience)
useEffect(() => {
const open = (e: KeyboardEvent) => {
if (e.key === '/' && showNewSearch && !isSearchOpen) {
e.preventDefault()
setIsSearchOpen(true)
}
}
window.addEventListener('keydown', open)
return () => window.removeEventListener('keydown', open)
}, [isSearchOpen, showNewSearch])

// For the UI in smaller browser widths, and focus the picker menu button when the search
// input is closed.
useEffect(() => {
Expand Down
7 changes: 6 additions & 1 deletion src/redirects/middleware/handle-redirects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ export default function handleRedirects(req: ExtendedRequest, res: Response, nex
if (req.path === '/') {
const language = getLanguage(req)
languageCacheControl(res)
return res.redirect(302, `/${language}`)
// Forward query params to the new URL
let queryParams = new URLSearchParams((req?.query as any) || '').toString()
if (queryParams) {
queryParams = `?${queryParams}`
}
return res.redirect(302, `/${language}${queryParams}`)
}

// begin redirect handling
Expand Down
2 changes: 1 addition & 1 deletion src/search/components/helpers/ai-search-links-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type LinksJSON = Array<{
//
// We include the JSON string in our analytics events so we can see the
// most popular sourced references, among other things.
export function generateAiSearchLinksJson(
export function generateAISearchLinksJson(
sourcesBuffer: Array<{ url: string }>,
aiResponse: string,
): string {
Expand Down
Loading

0 comments on commit be0208b

Please sign in to comment.