@@ -23,7 +23,8 @@ type Props = {
|
||||
// Homepage and 404 should be `isStandalone`, all others not
|
||||
// `updateSearchParams` should be false on the GraphQL explorer page
|
||||
export function Search({ isStandalone = false, updateSearchParams = true, children }: Props) {
|
||||
const [query, setQuery] = useState('')
|
||||
const router = useRouter()
|
||||
const [query, setQuery] = useState(router.query.query || '')
|
||||
const [results, setResults] = useState<Array<SearchResult>>([])
|
||||
const [activeHit, setActiveHit] = useState(0)
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
@@ -32,18 +33,14 @@ export function Search({ isStandalone = false, updateSearchParams = true, childr
|
||||
|
||||
// Figure out language and version for index
|
||||
const { languages, searchVersions, nonEnterpriseDefaultVersion } = useMainContext()
|
||||
const router = useRouter()
|
||||
// fall back to the non-enterprise default version (FPT currently) on the homepage, 404 page, etc.
|
||||
const version = searchVersions[currentVersion] || searchVersions[nonEnterpriseDefaultVersion]
|
||||
const language = (Object.keys(languages).includes(router.locale || '') && router.locale) || 'en'
|
||||
|
||||
// If the user shows up with a query in the URL, go ahead and search for it
|
||||
useEffect(() => {
|
||||
const params = new URLSearchParams(location.search)
|
||||
if (params.has('query')) {
|
||||
const xquery = params.get('query')?.trim() || ''
|
||||
setQuery(xquery)
|
||||
/* await */ fetchSearchResults(xquery)
|
||||
if (router.query.query) {
|
||||
/* await */ fetchSearchResults((router.query.query as string).trim())
|
||||
}
|
||||
}, [])
|
||||
|
||||
@@ -183,7 +180,7 @@ export function Search({ isStandalone = false, updateSearchParams = true, childr
|
||||
</div>
|
||||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
|
||||
<div
|
||||
className={'search-overlay-desktop' + (!isStandalone && query ? ' js-open' : '')}
|
||||
className={cx('search-overlay-desktop', !isStandalone && query ? 'js-open' : '')}
|
||||
onClick={closeSearch}
|
||||
></div>
|
||||
</>
|
||||
|
||||
@@ -35,7 +35,7 @@ export const Survey = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<form className="f5" onSubmit={submit} ref={formRef}>
|
||||
<form className="f5" onSubmit={submit} ref={formRef} data-testid="survey-form">
|
||||
<h2 className="mb-1 f4">
|
||||
{t`able_to_find`}
|
||||
|
||||
@@ -128,7 +128,7 @@ export const Survey = () => {
|
||||
</>
|
||||
)}
|
||||
|
||||
{state === ViewState.END && <p className="color-text-secondary f6">{t`feedback`}</p>}
|
||||
{state === ViewState.END && <p className="color-text-secondary f6" data-testid="survey-end">{t`feedback`}</p>}
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ export type FeaturedTrack = {
|
||||
trackName: string
|
||||
title: string
|
||||
description: string
|
||||
guides?: Array<{ href: string; page: { type: string }; title: string; intro: string }>
|
||||
guides?: Array<{ href: string; page?: { type: string }; title: string; intro: string }>
|
||||
} | null
|
||||
|
||||
export type ArticleGuide = {
|
||||
|
||||
@@ -36,7 +36,7 @@ export function GHESReleaseNotes({ context }: Props) {
|
||||
{prevRelease ? (
|
||||
<Link
|
||||
className="btn btn-outline"
|
||||
href={`/${currentLanguage}/${currentVersion.plan}@${prevRelease}/${currentProduct}/release-notes`}
|
||||
href={`/${currentLanguage}/${currentVersion.plan}@${prevRelease}/${currentProduct?.id}/release-notes`}
|
||||
>
|
||||
<ChevronLeftIcon /> {prevRelease}
|
||||
</Link>
|
||||
@@ -51,7 +51,7 @@ export function GHESReleaseNotes({ context }: Props) {
|
||||
{nextRelease ? (
|
||||
<Link
|
||||
className="btn btn-outline"
|
||||
href={`/${currentLanguage}/${currentVersion.plan}@${nextRelease}/${currentProduct}/release-notes`}
|
||||
href={`/${currentLanguage}/${currentVersion.plan}@${nextRelease}/${currentProduct?.id}/release-notes`}
|
||||
>
|
||||
{nextRelease} <ChevronRightIcon />
|
||||
</Link>
|
||||
|
||||
@@ -7,16 +7,17 @@ type Props = {
|
||||
|
||||
export const ArticleCard = ({ card, typeLabel }: Props) => {
|
||||
return (
|
||||
<div className="d-flex col-12 col-md-4 pr-0 pr-md-6 pr-lg-8">
|
||||
<div data-testid="article-card" className="d-flex col-12 col-md-4 pr-0 pr-md-6 pr-lg-8">
|
||||
<a className="no-underline d-flex flex-column py-3 border-bottom" href={card.href}>
|
||||
<h4 className="h4 color-text-primary mb-1">{card.title}</h4>
|
||||
<div className="h6 text-uppercase">{typeLabel}</div>
|
||||
<div className="h6 text-uppercase" data-testid="article-card-type">{typeLabel}</div>
|
||||
<p className="color-text-secondary my-3">{card.intro}</p>
|
||||
{card.topics.length > 0 && (
|
||||
<div>
|
||||
{card.topics.map((topic) => {
|
||||
return (
|
||||
<span
|
||||
data-testid="article-card-topic"
|
||||
key={topic}
|
||||
className="IssueLabel bg-gradient--pink-blue color-text-inverse mr-1"
|
||||
>
|
||||
|
||||
@@ -50,6 +50,7 @@ export const ArticleCards = () => {
|
||||
className="form-select f4 text-bold border-0 rounded-0 border-top box-shadow-none pl-0"
|
||||
name="type"
|
||||
aria-label="guide types"
|
||||
data-testid="card-filter-dropdown"
|
||||
onChange={onChangeTypeFilter}
|
||||
>
|
||||
<option value="">{t('filters.all')}</option>
|
||||
@@ -70,6 +71,7 @@ export const ArticleCards = () => {
|
||||
value={topicFilter}
|
||||
className="form-select f4 text-bold border-0 rounded-0 border-top box-shadow-none pl-0"
|
||||
name="topics"
|
||||
data-testid="card-filter-dropdown"
|
||||
aria-label="guide topics"
|
||||
onChange={onChangeTopicFilter}
|
||||
>
|
||||
|
||||
@@ -53,7 +53,7 @@ export const LearningTrack = ({ track }: Props) => {
|
||||
</div>
|
||||
<h5 className="flex-auto pr-2">{guide.title}</h5>
|
||||
<div className="color-text-tertiary h6 text-uppercase flex-shrink-0">
|
||||
{t('guide_types')[guide.page.type]}
|
||||
{t('guide_types')[guide.page?.type || '']}
|
||||
</div>
|
||||
</a>
|
||||
{track?.guides && track?.guides?.indexOf(guide) + 1 === MAX_VISIBLE_GUIDES ? (
|
||||
|
||||
@@ -26,7 +26,7 @@ export const SubLandingHero = () => {
|
||||
)}
|
||||
</div>
|
||||
<div className="color-text-tertiary h6 text-uppercase">
|
||||
{t('guide_types')[guide.page.type]}
|
||||
{t('guide_types')[guide.page?.type || '']}
|
||||
</div>
|
||||
</div>
|
||||
<h3 className="font-mktg h3-mktg my-4 color-text-primary">{guide.title}</h3>
|
||||
|
||||
@@ -9,7 +9,7 @@ topics:
|
||||
|
||||
{% data reusables.codespaces.release-stage %}
|
||||
|
||||
When you enable access and security for a repository owned by your user account, any codespaces that are created for that repository will have read and write permissions to all other repositories you own. If you want to restrict the repositories a codespace can access, you can limit to it to either the repository the codespace was opened for or specific repositories. You should only enable access and security for repositories you trust.
|
||||
When you enable access and security for a repository owned by your user account, any codespaces that are created for that repository will have read permissions to all other repositories you own. If you want to restrict the repositories a codespace can access, you can limit to it to either the repository the codespace was opened for or specific repositories. You should only enable access and security for repositories you trust.
|
||||
|
||||
{% data reusables.user_settings.access_settings %}
|
||||
{% data reusables.user_settings.codespaces-tab %}
|
||||
|
||||
@@ -73494,6 +73494,16 @@
|
||||
},
|
||||
"descriptionHTML": "<p>Set to <code>open</code> or <code>resolved</code> to only list secret scanning alerts in a specific state.</p>"
|
||||
},
|
||||
{
|
||||
"name": "secret_types",
|
||||
"in": "query",
|
||||
"description": "Set to a comma seperate list of secret_types to only list secret scanning alerts in for those types. Set to `all` to list all the secret scanning alerts. Default is `all`",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"descriptionHTML": "<p>Set to a comma seperate list of secret_types to only list secret scanning alerts in for those types. Set to <code>all</code> to list all the secret scanning alerts. Default is <code>all</code></p>"
|
||||
},
|
||||
{
|
||||
"name": "page",
|
||||
"description": "Page number of the results to fetch.",
|
||||
|
||||
@@ -71285,6 +71285,16 @@
|
||||
},
|
||||
"descriptionHTML": "<p>Set to <code>open</code> or <code>resolved</code> to only list secret scanning alerts in a specific state.</p>"
|
||||
},
|
||||
{
|
||||
"name": "secret_types",
|
||||
"in": "query",
|
||||
"description": "Set to a comma seperate list of secret_types to only list secret scanning alerts in for those types. Set to `all` to list all the secret scanning alerts. Default is `all`",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"descriptionHTML": "<p>Set to a comma seperate list of secret_types to only list secret scanning alerts in for those types. Set to <code>all</code> to list all the secret scanning alerts. Default is <code>all</code></p>"
|
||||
},
|
||||
{
|
||||
"name": "page",
|
||||
"description": "Page number of the results to fetch.",
|
||||
|
||||
@@ -323443,6 +323443,15 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "secret_types",
|
||||
"in": "query",
|
||||
"description": "Set to a comma seperate list of secret_types to only list secret scanning alerts in for those types. Set to `all` to list all the secret scanning alerts. Default is `all`",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "page",
|
||||
"description": "Page number of the results to fetch.",
|
||||
|
||||
@@ -307187,6 +307187,15 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "secret_types",
|
||||
"in": "query",
|
||||
"description": "Set to a comma seperate list of secret_types to only list secret scanning alerts in for those types. Set to `all` to list all the secret scanning alerts. Default is `all`",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "page",
|
||||
"description": "Page number of the results to fetch.",
|
||||
|
||||
@@ -5,29 +5,6 @@ const versionIds = Object.keys(require('../lib/all-versions'))
|
||||
|
||||
const { FEATURE_NEXTJS } = process.env;
|
||||
|
||||
const enabledSubSections = [
|
||||
// 'actions',
|
||||
// 'admin',
|
||||
"billing",
|
||||
// "code-security",
|
||||
// "codespaces",
|
||||
"communities",
|
||||
"desktop",
|
||||
// "developers",
|
||||
"discussions",
|
||||
// 'early-access',
|
||||
"education",
|
||||
// 'github',
|
||||
// "graphql",
|
||||
// 'insights',
|
||||
// "issues",
|
||||
"organizations",
|
||||
'packages',
|
||||
"pages",
|
||||
"rest",
|
||||
"sponsors",
|
||||
];
|
||||
|
||||
const homePageExp = pathToRegexp('/:locale/:versionId?')
|
||||
const productPageExp = pathToRegexp('/:locale/:versionId?/:productId')
|
||||
const subSectionExp = pathToRegexp('/:locale/:versionId?/:productId/:subSection*')
|
||||
@@ -53,8 +30,7 @@ module.exports = function isNextRequest(req, res, next) {
|
||||
} else if (productPageMatch && productIds.includes(productPageMatch[3])) {
|
||||
req.renderWithNextjs = true
|
||||
} else if (subSectionMatch) {
|
||||
// depending on whether versionId is included the productId is in a different place
|
||||
req.renderWithNextjs = enabledSubSections.includes(subSectionMatch[2]) || enabledSubSections.includes(subSectionMatch[3])
|
||||
req.renderWithNextjs = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ header {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@include breakpoint(md) {
|
||||
@include breakpoint(lg) {
|
||||
#search-results-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
|
||||
@@ -43,7 +43,7 @@ describe('browser search', () => {
|
||||
await page.waitForSelector('.ais-Hits')
|
||||
const hits = await page.$$('.ais-Hits-item')
|
||||
expect(hits.length).toBeGreaterThan(5)
|
||||
page.setViewport(initialViewport)
|
||||
await page.setViewport(initialViewport)
|
||||
})
|
||||
|
||||
it('works on 404 error page', async () => {
|
||||
@@ -71,8 +71,10 @@ describe('browser search', () => {
|
||||
interceptedRequest.continue()
|
||||
})
|
||||
|
||||
await newPage.click('#search-input-container input[type="search"]')
|
||||
await newPage.type('#search-input-container input[type="search"]', 'test')
|
||||
await newPage.click('[data-testid=mobile-menu-button]')
|
||||
const searchInput = await newPage.$('[data-testid=mobile-header] [data-testid=site-search-input]')
|
||||
await searchInput.click()
|
||||
await searchInput.type('test')
|
||||
await newPage.waitForSelector('.search-result')
|
||||
})
|
||||
|
||||
@@ -92,8 +94,10 @@ describe('browser search', () => {
|
||||
interceptedRequest.continue()
|
||||
})
|
||||
|
||||
await newPage.click('#search-input-container input[type="search"]')
|
||||
await newPage.type('#search-input-container input[type="search"]', 'test')
|
||||
await newPage.click('[data-testid=mobile-menu-button]')
|
||||
const searchInput = await newPage.$('[data-testid=mobile-header] [data-testid=site-search-input]')
|
||||
await searchInput.click()
|
||||
await searchInput.type('test')
|
||||
await newPage.waitForSelector('.search-result')
|
||||
})
|
||||
})
|
||||
@@ -117,20 +121,20 @@ describe('survey', () => {
|
||||
})
|
||||
|
||||
// When I click the "Yes" button
|
||||
await page.click('.js-survey [for=survey-yes]')
|
||||
await page.click('[data-testid=survey-form] [for=survey-yes]')
|
||||
// (sent a POST request to /events)
|
||||
// I see the request for my email
|
||||
await page.waitForSelector('.js-survey [type="email"]')
|
||||
await page.waitForSelector('[data-testid=survey-form] [type="email"]')
|
||||
|
||||
// When I fill in my email and submit the form
|
||||
await page.type('.js-survey [type="email"]', 'test@example.com')
|
||||
await page.type('[data-testid=survey-form] [type="email"]', 'test@example.com')
|
||||
|
||||
await sleep(1000)
|
||||
|
||||
await page.click('.js-survey [type="submit"]')
|
||||
await page.click('[data-testid=survey-form] [type="submit"]')
|
||||
// (sent a PUT request to /events/{id})
|
||||
// I see the feedback
|
||||
await page.waitForSelector('.js-survey [data-help-end]')
|
||||
await page.waitForSelector('[data-testid=survey-end]')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -257,23 +261,23 @@ describe('code examples', () => {
|
||||
describe('filter cards', () => {
|
||||
it('works with select input', async () => {
|
||||
await page.goto('http://localhost:4001/en/actions/guides')
|
||||
await page.select('.js-filter-card-filter-dropdown[name="type"]', 'overview')
|
||||
const shownCards = await page.$$('.js-filter-card:not(.d-none)')
|
||||
const shownCardsAttrib = await page.$$eval('.js-filter-card:not(.d-none)', cards =>
|
||||
cards.map(card => card.dataset.type)
|
||||
await page.select('[data-testid=card-filter-dropdown][name="type"]', 'overview')
|
||||
const shownCards = await page.$$('[data-testid=article-card]')
|
||||
const shownCardTypes = await page.$$eval('[data-testid=article-card-type]', cardTypes =>
|
||||
cardTypes.map(cardType => cardType.textContent)
|
||||
)
|
||||
shownCardsAttrib.map(attrib => expect(attrib).toBe('overview'))
|
||||
shownCardTypes.map(type => expect(type).toBe('Overview'))
|
||||
expect(shownCards.length).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it('works with select input on an Enterprise version', async () => {
|
||||
await page.goto(`http://localhost:4001/en/enterprise-server@${latest}/actions/guides`)
|
||||
await page.select('.js-filter-card-filter-dropdown[name="type"]', 'overview')
|
||||
const shownCards = await page.$$('.js-filter-card:not(.d-none)')
|
||||
const shownCardsAttrib = await page.$$eval('.js-filter-card:not(.d-none)', cards =>
|
||||
cards.map(card => card.dataset.type)
|
||||
await page.select('[data-testid=card-filter-dropdown][name="type"]', 'overview')
|
||||
const shownCards = await page.$$('[data-testid=article-card]')
|
||||
const shownCardTypes = await page.$$eval('[data-testid=article-card-type]', cardTypes =>
|
||||
cardTypes.map(cardType => cardType.textContent)
|
||||
)
|
||||
shownCardsAttrib.map(attrib => expect(attrib).toBe('overview'))
|
||||
shownCardTypes.map(type => expect(type).toBe('Overview'))
|
||||
expect(shownCards.length).toBeGreaterThan(0)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -34,12 +34,12 @@ describe('sidebar', () => {
|
||||
test('adds an `is-current-page` class to the sidebar link to the current page', async () => {
|
||||
const url = '/en/github/setting-up-and-managing-your-github-user-account/managing-user-account-settings'
|
||||
const $ = await getDOM(url)
|
||||
expect($('.sidebar .is-current-page').length).toBe(1)
|
||||
expect($('.sidebar .is-current-page a').attr('href')).toContain(url)
|
||||
expect($('.sidebar-products .is-current-page').length).toBe(1)
|
||||
expect($('.sidebar-products .is-current-page a').attr('href')).toContain(url)
|
||||
})
|
||||
|
||||
test('does not display Early Access as a product', async () => {
|
||||
expect($homePage('.sidebar li.sidebar-product[title*="Early"]').length).toBe(0)
|
||||
expect($homePage('.sidebar li.sidebar-product[title*="early"]').length).toBe(0)
|
||||
expect($homePage('.sidebar-products li.sidebar-product[title*="Early"]').length).toBe(0)
|
||||
expect($homePage('.sidebar-products li.sidebar-product[title*="early"]').length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user