diff --git a/assets/images/help/command-palette/command-palette-keyboard-shortcut-settings.png b/assets/images/help/command-palette/command-palette-keyboard-shortcut-settings.png
new file mode 100644
index 0000000000..badbe6cdeb
Binary files /dev/null and b/assets/images/help/command-palette/command-palette-keyboard-shortcut-settings.png differ
diff --git a/components/sidebar/AllProductsLink.tsx b/components/sidebar/AllProductsLink.tsx
index 4a67b33541..beecbab575 100644
--- a/components/sidebar/AllProductsLink.tsx
+++ b/components/sidebar/AllProductsLink.tsx
@@ -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 (
-
+
All products
diff --git a/components/sidebar/SidebarHomepage.tsx b/components/sidebar/SidebarHomepage.tsx
index 93c78600d8..e94a5fa1c7 100644
--- a/components/sidebar/SidebarHomepage.tsx
+++ b/components/sidebar/SidebarHomepage.tsx
@@ -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 (
- {!isFPT && }
-
diff --git a/content/get-started/using-github/github-command-palette.md b/content/get-started/using-github/github-command-palette.md
index 9ba9add110..bb08acddd0 100644
--- a/content/get-started/using-github/github-command-palette.md
+++ b/content/get-started/using-github/github-command-palette.md
@@ -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: Ctrl+K or Ctrl+Alt+K
- Mac: Command+K or Command+Option+K
+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 Ctrl+Shift+K (Windows and Linux) or Command+Shift+K (Mac) to open the command palette in command mode. If you already have the command palette open, press > 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 Ctrl+Shift+K (Windows and Linux) or Command+Shift+K (Mac). If you already have the command palette open, press > 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 Enter 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: Esc or Ctrl+K (Windows and Linux) Command+K (Mac)
- Command mode: Esc or Ctrl+Shift+K (Windows and Linux) Command+Shift+K (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
diff --git a/lib/page.js b/lib/page.js
index 5554a43f82..20a1e48cce 100644
--- a/lib/page.js
+++ b/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.
diff --git a/middleware/render-page.js b/middleware/render-page.js
index 5e988c478d..2223f9e3b1 100644
--- a/middleware/render-page.js
+++ b/middleware/render-page.js
@@ -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
diff --git a/tests/rendering/server.js b/tests/rendering/server.js
index b6d75ece2f..9bda85f634 100644
--- a/tests/rendering/server.js
+++ b/tests/rendering/server.js
@@ -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(', ')}`
diff --git a/tests/unit/page.js b/tests/unit/page.js
index 63570c0f9f..9f22398d2d 100644
--- a/tests/unit/page.js
+++ b/tests/unit/page.js
@@ -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()