Merge branch 'main' into graphql-schema-update
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
@@ -1,11 +1,18 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import { ArrowLeftIcon } from '@primer/octicons-react'
|
||||
import { DEFAULT_VERSION, useVersion } from 'components/hooks/useVersion'
|
||||
|
||||
export const AllProductsLink = () => {
|
||||
const router = useRouter()
|
||||
const { currentVersion } = useVersion()
|
||||
const currentVersionPathSegment = currentVersion === DEFAULT_VERSION ? '' : `/${currentVersion}`
|
||||
|
||||
return (
|
||||
<li>
|
||||
<a href={`/${router.locale}`} className="f6 pl-4 pr-5 ml-n1 pb-1 color-fg-default">
|
||||
<a
|
||||
href={`/${router.locale}${currentVersionPathSegment}`}
|
||||
className="f6 pl-4 pr-5 ml-n1 pb-1 color-fg-default"
|
||||
>
|
||||
<ArrowLeftIcon size="small" className="mr-1" />
|
||||
All products
|
||||
</a>
|
||||
|
||||
@@ -6,8 +6,6 @@ import { useVersion } from 'components/hooks/useVersion'
|
||||
import { useMainContext } from 'components/context/MainContext'
|
||||
import { Link } from 'components/Link'
|
||||
|
||||
import { AllProductsLink } from './AllProductsLink'
|
||||
|
||||
export const SidebarHomepage = () => {
|
||||
const router = useRouter()
|
||||
const { currentVersion } = useVersion()
|
||||
@@ -55,7 +53,6 @@ export const SidebarHomepage = () => {
|
||||
|
||||
return (
|
||||
<ul data-testid="sidebar" className="mt-4">
|
||||
{!isFPT && <AllProductsLink />}
|
||||
<li>
|
||||
<ActionList {...{ as: 'ul' }} items={navItems}></ActionList>
|
||||
</li>
|
||||
|
||||
@@ -26,10 +26,12 @@ The ability to run commands directly from your keyboard, without navigating thro
|
||||
|
||||
## Opening the {% data variables.product.prodname_command_palette %}
|
||||
|
||||
Open the command palette using one of the following keyboard shortcuts:
|
||||
Open the command palette using one of the following default keyboard shortcuts:
|
||||
- Windows and Linux: <kbd>Ctrl</kbd>+<kbd>K</kbd> or <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>K</kbd>
|
||||
- Mac: <kbd>Command</kbd>+<kbd>K</kbd> or <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>K</kbd>
|
||||
|
||||
You can customize the keyboard shortcuts you use to open the command palette in the [Accessibility section](https://github.com/settings/accessibility) of your user settings. For more information, see "[Customizing your {% data variables.product.prodname_command_palette %} keyboard shortcuts](#customizing-your-github-command-palette-keyboard-shortcuts)."
|
||||
|
||||
When you open the command palette, it shows your location at the top left and uses it as the scope for suggestions (for example, the `mashed-avocado` organization).
|
||||
|
||||

|
||||
@@ -42,6 +44,12 @@ When you open the command palette, it shows your location at the top left and us
|
||||
|
||||
{% endnote %}
|
||||
|
||||
### Customizing your {% data variables.product.prodname_command_palette %} keyboard shortcuts
|
||||
|
||||
|
||||
The default keyboard shortcuts used to open the command palette may conflict with your default OS and browser keyboard shortcuts. You have the option to customize your keyboard shortcuts in the [Accessibility section](https://github.com/settings/accessibility) of your account settings. In the command palette settings, you can customize the keyboard shortcuts for opening the command palette in both search mode and command mode.
|
||||
|
||||

|
||||
## Navigating with the {% data variables.product.prodname_command_palette %}
|
||||
|
||||
You can use the command palette to navigate to any page that you have access to on {% data variables.product.product_name %}.
|
||||
@@ -96,7 +104,7 @@ You can use the {% data variables.product.prodname_command_palette %} to run com
|
||||
|
||||
For a full list of supported commands, see "[{% data variables.product.prodname_command_palette %} reference](#github-command-palette-reference)."
|
||||
|
||||
1. Use <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>K</kbd> (Windows and Linux) or <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>K</kbd> (Mac) to open the command palette in command mode. If you already have the command palette open, press <kbd>></kbd> to switch to command mode. {% data variables.product.prodname_dotcom %} suggests commands based on your location.
|
||||
1. The default keyboard shortcuts to open the command palette in command mode are <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>K</kbd> (Windows and Linux) or <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>K</kbd> (Mac). If you already have the command palette open, press <kbd>></kbd> to switch to command mode. {% data variables.product.prodname_dotcom %} suggests commands based on your location.
|
||||
|
||||

|
||||
|
||||
@@ -106,6 +114,7 @@ For a full list of supported commands, see "[{% data variables.product.prodname_
|
||||
|
||||
4. Use the arrow keys to highlight the command you want and use <kbd>Enter</kbd> to run it.
|
||||
|
||||
|
||||
## Closing the command palette
|
||||
|
||||
When the command palette is active, you can use one of the following keyboard shortcuts to close the command palette:
|
||||
@@ -113,6 +122,8 @@ When the command palette is active, you can use one of the following keyboard sh
|
||||
- Search and navigation mode: <kbd>Esc</kbd> or <kbd>Ctrl</kbd>+<kbd>K</kbd> (Windows and Linux) <kbd>Command</kbd>+<kbd>K</kbd> (Mac)
|
||||
- Command mode: <kbd>Esc</kbd> or <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>K</kbd> (Windows and Linux) <kbd>Command</kbd>+<kbd>Shift</kbd>+<kbd>K</kbd> (Mac)
|
||||
|
||||
If you have customized the command palette keyboard shortcuts in the Accessibility settings, your customized keyboard shortcuts will be used for both opening and closing the command palette.
|
||||
|
||||
## {% data variables.product.prodname_command_palette %} reference
|
||||
|
||||
### Keystroke functions
|
||||
|
||||
40
lib/page.js
40
lib/page.js
@@ -18,6 +18,22 @@ import getLinkData from './get-link-data.js'
|
||||
import getDocumentType from './get-document-type.js'
|
||||
import { union } from 'lodash-es'
|
||||
|
||||
// Wrapper on renderContent() that caches the output depending on the
|
||||
// `context` by extracting information about the page's current permalink
|
||||
const _renderContentCache = new Map()
|
||||
|
||||
function renderContentCacheByContext(prefix) {
|
||||
return async function (template = '', context = {}, options = {}) {
|
||||
const { currentPath } = context
|
||||
const cacheKey = prefix + currentPath
|
||||
|
||||
if (!_renderContentCache.has(cacheKey)) {
|
||||
_renderContentCache.set(cacheKey, await renderContent(template, context, options))
|
||||
}
|
||||
return _renderContentCache.get(cacheKey)
|
||||
}
|
||||
}
|
||||
|
||||
class Page {
|
||||
static async init(opts) {
|
||||
opts = await Page.read(opts)
|
||||
@@ -165,17 +181,22 @@ class Page {
|
||||
context.englishHeadings = englishHeadings
|
||||
}
|
||||
|
||||
this.intro = await renderContent(this.rawIntro, context)
|
||||
this.introPlainText = await renderContent(this.rawIntro, context, { textOnly: true })
|
||||
this.title = await renderContent(this.rawTitle, context, {
|
||||
this.intro = await renderContentCacheByContext('intro')(this.rawIntro, context)
|
||||
this.introPlainText = await renderContentCacheByContext('rawIntro')(this.rawIntro, context, {
|
||||
textOnly: true,
|
||||
})
|
||||
this.title = await renderContentCacheByContext('rawTitle')(this.rawTitle, context, {
|
||||
textOnly: true,
|
||||
encodeEntities: true,
|
||||
})
|
||||
this.titlePlainText = await renderContent(this.rawTitle, context, { textOnly: true })
|
||||
this.shortTitle = await renderContent(this.shortTitle, context, {
|
||||
this.titlePlainText = await renderContentCacheByContext('titleText')(this.rawTitle, context, {
|
||||
textOnly: true,
|
||||
})
|
||||
this.shortTitle = await renderContentCacheByContext('shortTitle')(this.shortTitle, context, {
|
||||
textOnly: true,
|
||||
encodeEntities: true,
|
||||
})
|
||||
|
||||
this.product_video = await renderContent(this.raw_product_video, context, { textOnly: true })
|
||||
|
||||
if (this.introLinks) {
|
||||
@@ -191,7 +212,7 @@ class Page {
|
||||
}
|
||||
|
||||
context.relativePath = this.relativePath
|
||||
const html = await renderContent(this.markdown, context)
|
||||
const html = await renderContentCacheByContext('markdown')(this.markdown, context)
|
||||
|
||||
// Adding communityRedirect for Discussions, Sponsors, and Codespaces - request from Product
|
||||
if (
|
||||
@@ -208,12 +229,15 @@ class Page {
|
||||
|
||||
// product frontmatter may contain liquid
|
||||
if (this.product) {
|
||||
this.product = await renderContent(this.rawProduct, context)
|
||||
this.product = await renderContentCacheByContext('product')(this.rawProduct, context)
|
||||
}
|
||||
|
||||
// permissions frontmatter may contain liquid
|
||||
if (this.permissions) {
|
||||
this.permissions = await renderContent(this.rawPermissions, context)
|
||||
this.permissions = await renderContentCacheByContext('permissions')(
|
||||
this.rawPermissions,
|
||||
context
|
||||
)
|
||||
}
|
||||
|
||||
// Learning tracks may contain Liquid and need to have versioning processed.
|
||||
|
||||
@@ -7,37 +7,6 @@ import statsd from '../lib/statsd.js'
|
||||
import { isConnectionDropped } from './halt-on-dropped-connection.js'
|
||||
import { nextApp, nextHandleRequest } from './next.js'
|
||||
|
||||
function cacheOnReq(fn) {
|
||||
const cache = new Map()
|
||||
|
||||
return async function (req) {
|
||||
const path = req.pagePath || req.path
|
||||
|
||||
// Is the request for the GraphQL Explorer page?
|
||||
const isGraphQLExplorer =
|
||||
req.context.currentPathWithoutLanguage === '/graphql/overview/explorer'
|
||||
|
||||
// Serve from the cache if possible
|
||||
const isCacheable =
|
||||
// Skip for HTTP methods other than GET
|
||||
req.method === 'GET' &&
|
||||
// Skip for JSON debugging info requests
|
||||
!('json' in req.query) &&
|
||||
// Skip for the GraphQL Explorer page
|
||||
!isGraphQLExplorer
|
||||
|
||||
if (isCacheable && cache.has(path)) {
|
||||
return cache.get(path)
|
||||
}
|
||||
const result = await fn(req)
|
||||
|
||||
if (result && isCacheable) {
|
||||
cache.set(path, result)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
async function buildRenderedPage(req) {
|
||||
const { context } = req
|
||||
const { page } = context
|
||||
@@ -77,8 +46,6 @@ async function buildMiniTocItems(req) {
|
||||
return getMiniTocItems(context.renderedPage, page.miniTocMaxHeadingLevel)
|
||||
}
|
||||
|
||||
const wrapRenderedPage = cacheOnReq(buildRenderedPage)
|
||||
|
||||
export default async function renderPage(req, res, next) {
|
||||
const { context } = req
|
||||
const { page } = context
|
||||
@@ -114,7 +81,7 @@ export default async function renderPage(req, res, next) {
|
||||
// Stop processing if the connection was already dropped
|
||||
if (isConnectionDropped(req, res)) return
|
||||
|
||||
req.context.renderedPage = await wrapRenderedPage(req)
|
||||
req.context.renderedPage = await buildRenderedPage(req)
|
||||
req.context.miniTocItems = await buildMiniTocItems(req)
|
||||
|
||||
// Stop processing if the connection was already dropped
|
||||
|
||||
@@ -88,15 +88,10 @@ describe('server', () => {
|
||||
const productTitles = productItems.map((el) => $(el).text().trim())
|
||||
const productHrefs = productItems.map((el) => $(el).attr('href'))
|
||||
|
||||
const firstSidebarTitle = sidebarTitles.shift()
|
||||
const firstSidebarHref = sidebarHrefs.shift()
|
||||
|
||||
const titlesInProductsButNotSidebar = lodash.difference(productTitles, sidebarTitles)
|
||||
|
||||
const hrefsInProductsButNotSidebar = lodash.difference(productHrefs, sidebarHrefs)
|
||||
|
||||
expect(firstSidebarTitle).toBe('All products')
|
||||
expect(firstSidebarHref).toBe('/en')
|
||||
expect(
|
||||
titlesInProductsButNotSidebar.length,
|
||||
`Found titles missing from sidebar: ${titlesInProductsButNotSidebar.join(', ')}`
|
||||
|
||||
@@ -134,6 +134,10 @@ describe('Page class', () => {
|
||||
'/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-branches',
|
||||
currentLanguage: 'en',
|
||||
}
|
||||
// This is needed because unit tests are weird. The page.render()
|
||||
// method is dependent on module global cache.
|
||||
// We need to fudge the `currentPath` so it appears to be different.
|
||||
context.currentPath += Math.random()
|
||||
await page.render(context)
|
||||
const $ = cheerio.load(page.intro)
|
||||
expect(
|
||||
@@ -208,6 +212,7 @@ describe('Page class', () => {
|
||||
currentLanguage: 'en',
|
||||
enterpriseServerVersions,
|
||||
}
|
||||
context.currentPath = `/${context.currentLanguage}/${context.currentVersion}/${page.relativePath}`
|
||||
let rendered = await page.render(context)
|
||||
let $ = cheerio.load(rendered)
|
||||
expect($.text()).toBe(
|
||||
@@ -218,6 +223,7 @@ describe('Page class', () => {
|
||||
// change version to the oldest enterprise version, re-render, and test again;
|
||||
// the results should be the same
|
||||
context.currentVersion = `enterprise-server@${enterpriseServerReleases.oldestSupported}`
|
||||
context.currentPath = `/${context.currentLanguage}/${context.currentVersion}/${page.relativePath}`
|
||||
rendered = await page.render(context)
|
||||
$ = cheerio.load(rendered)
|
||||
expect($.text()).toBe(
|
||||
@@ -228,6 +234,7 @@ describe('Page class', () => {
|
||||
// change version to non-enterprise, re-render, and test again;
|
||||
// the results should be the opposite
|
||||
context.currentVersion = nonEnterpriseDefaultVersion
|
||||
context.currentPath = `/${context.currentLanguage}/${context.currentVersion}/${page.relativePath}`
|
||||
rendered = await page.render(context)
|
||||
$ = cheerio.load(rendered)
|
||||
expect($.text()).not.toBe(
|
||||
@@ -265,6 +272,7 @@ describe('Page class', () => {
|
||||
currentVersion: 'github-ae@latest',
|
||||
currentLanguage: 'en',
|
||||
}
|
||||
context.currentPath = `/${context.currentLanguage}/${context.currentVersion}`
|
||||
await expect(() => {
|
||||
return page.render(context)
|
||||
}).not.toThrow()
|
||||
|
||||
Reference in New Issue
Block a user