Merge branch 'main' into patch-2
This commit is contained in:
3
.github/workflows/staging-deploy-pr.yml
vendored
3
.github/workflows/staging-deploy-pr.yml
vendored
@@ -136,8 +136,7 @@ jobs:
|
||||
target_url: ACTIONS_RUN_LOG
|
||||
})
|
||||
|
||||
- if: ${{ github.repository == 'github/docs-internal' }}
|
||||
name: Check out repo's default branch
|
||||
- name: Check out repo's default branch
|
||||
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
||||
with:
|
||||
# To prevent issues with cloning early access content later
|
||||
|
||||
BIN
assets/images/help/writing/display-markdown-as-source.png
Normal file
BIN
assets/images/help/writing/display-markdown-as-source.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
@@ -37,7 +37,7 @@ export function Link(props: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<NextLink href={href || ''} locale={locale || false}>
|
||||
<NextLink href={locale ? `/${locale}${href}` : href || ''} locale={locale || false}>
|
||||
{/* eslint-disable-next-line jsx-a11y/anchor-has-content */}
|
||||
<a rel={isExternal ? 'noopener' : ''} {...restProps} />
|
||||
</NextLink>
|
||||
|
||||
@@ -171,7 +171,7 @@ export function Search({
|
||||
)}
|
||||
>
|
||||
{results.length > 0 ? (
|
||||
<ol data-testid="search-results" className="d-block mt-2">
|
||||
<ol data-testid="search-results" className="d-block mt-4">
|
||||
{results.map(({ url, breadcrumbs, heading, title, content }, index) => {
|
||||
const isActive = index === activeHit
|
||||
return (
|
||||
|
||||
126
components/VersionPicker.tsx
Normal file
126
components/VersionPicker.tsx
Normal file
@@ -0,0 +1,126 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import cx from 'classnames'
|
||||
import { Dropdown, Heading, Details, Box, Text, useDetails } from '@primer/components'
|
||||
import { ArrowRightIcon, ChevronDownIcon } from '@primer/octicons-react'
|
||||
|
||||
import { Link } from 'components/Link'
|
||||
import { useMainContext } from 'components/context/MainContext'
|
||||
import { useVersion } from 'components/hooks/useVersion'
|
||||
import { useTranslation } from 'components/hooks/useTranslation'
|
||||
|
||||
type Props = {
|
||||
hideLabel?: boolean
|
||||
variant?: 'default' | 'compact' | 'inline'
|
||||
popoverVariant?: 'inline' | 'dropdown'
|
||||
}
|
||||
export const VersionPicker = ({ variant = 'default', popoverVariant, hideLabel }: Props) => {
|
||||
const router = useRouter()
|
||||
const { currentVersion } = useVersion()
|
||||
const { allVersions, page, enterpriseServerVersions } = useMainContext()
|
||||
const { getDetailsProps, setOpen } = useDetails({ closeOnOutsideClick: true })
|
||||
const { t } = useTranslation('pages')
|
||||
|
||||
if (page.permalinks && page.permalinks.length <= 1) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{!hideLabel && (
|
||||
<Heading as="span" fontSize={1} className="d-none d-xl-inline-block mb-1">
|
||||
{t('article_version')}
|
||||
</Heading>
|
||||
)}
|
||||
<div>
|
||||
<Details
|
||||
{...getDetailsProps()}
|
||||
className={cx(
|
||||
'position-relative details-reset',
|
||||
variant === 'inline' ? 'd-block' : 'd-inline-block'
|
||||
)}
|
||||
data-testid="article-version-picker"
|
||||
>
|
||||
{(variant === 'compact' || variant === 'inline') && (
|
||||
<summary
|
||||
className="d-block btn btn-invisible color-text-primary"
|
||||
aria-haspopup="true"
|
||||
aria-label="Toggle version list"
|
||||
>
|
||||
{variant === 'inline' ? (
|
||||
<div className="d-flex flex-items-center flex-justify-between">
|
||||
<Text>{allVersions[currentVersion].versionTitle}</Text>
|
||||
<ChevronDownIcon size={24} className="arrow ml-md-1" />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<Text>{allVersions[currentVersion].versionTitle}</Text>
|
||||
<Dropdown.Caret />
|
||||
</>
|
||||
)}
|
||||
</summary>
|
||||
)}
|
||||
|
||||
{variant === 'default' && (
|
||||
<summary aria-haspopup="true" className="btn btn-sm">
|
||||
<Text>{allVersions[currentVersion].versionTitle}</Text>
|
||||
<Dropdown.Caret />
|
||||
</summary>
|
||||
)}
|
||||
|
||||
{popoverVariant === 'inline' ? (
|
||||
<Box py="2">
|
||||
{(page.permalinks || []).map((permalink) => {
|
||||
return (
|
||||
<Dropdown.Item key={permalink.href} onClick={() => setOpen(false)}>
|
||||
<Link href={permalink.href}>{permalink.pageVersionTitle}</Link>
|
||||
</Dropdown.Item>
|
||||
)
|
||||
})}
|
||||
<Box mt={1}>
|
||||
<Link
|
||||
onClick={() => {
|
||||
setOpen(false)
|
||||
}}
|
||||
href={`/${router.locale}/${enterpriseServerVersions[0]}/admin/all-releases`}
|
||||
className="f6 no-underline color-text-tertiary pl-3 pr-2 no-wrap"
|
||||
>
|
||||
{t('all_enterprise_releases')}{' '}
|
||||
<ArrowRightIcon verticalAlign="middle" size={15} className="mr-2" />
|
||||
</Link>
|
||||
</Box>
|
||||
</Box>
|
||||
) : (
|
||||
<Dropdown.Menu direction="sw" style={{ width: 'unset' }}>
|
||||
{(page.permalinks || []).map((permalink) => {
|
||||
return (
|
||||
<Dropdown.Item key={permalink.href} onClick={() => setOpen(false)}>
|
||||
<Link href={permalink.href}>{permalink.pageVersionTitle}</Link>
|
||||
</Dropdown.Item>
|
||||
)
|
||||
})}
|
||||
<Box
|
||||
borderColor="border.default"
|
||||
borderTopWidth={1}
|
||||
borderTopStyle="solid"
|
||||
mt={2}
|
||||
pt={2}
|
||||
pb={1}
|
||||
>
|
||||
<Link
|
||||
onClick={() => {
|
||||
setOpen(false)
|
||||
}}
|
||||
href={`/${router.locale}/${enterpriseServerVersions[0]}/admin/all-releases`}
|
||||
className="f6 no-underline color-text-tertiary pl-3 pr-2 no-wrap"
|
||||
>
|
||||
{t('all_enterprise_releases')}{' '}
|
||||
<ArrowRightIcon verticalAlign="middle" size={15} className="mr-2" />
|
||||
</Link>
|
||||
</Box>
|
||||
</Dropdown.Menu>
|
||||
)}
|
||||
</Details>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
@import "@primer/css/layout/index.scss";
|
||||
@import "@primer/css/support/variables/layout.scss";
|
||||
@import "@primer/css/marketing/support/variables.scss";
|
||||
|
||||
.container {
|
||||
max-width: 720px;
|
||||
|
||||
@include breakpoint(xl) {
|
||||
max-width: none;
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr;
|
||||
grid-template-columns: minmax(500px, 720px) minmax(220px, 1fr);
|
||||
grid-template-areas:
|
||||
"top right-sidebar"
|
||||
"bottom right-sidebar";
|
||||
column-gap: $spacer-6;
|
||||
}
|
||||
|
||||
@include breakpoint(xl) {
|
||||
column-gap: $spacer-9;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
grid-area: right-sidebar;
|
||||
}
|
||||
|
||||
.sidebarContent {
|
||||
@include breakpoint(xl) {
|
||||
position: sticky;
|
||||
top: $spacer-4;
|
||||
max-height: calc(100vh - #{$spacer-4});
|
||||
overflow-y: auto;
|
||||
padding-bottom: $spacer-4;
|
||||
}
|
||||
}
|
||||
|
||||
.head {
|
||||
grid-area: top;
|
||||
}
|
||||
|
||||
.content {
|
||||
grid-area: bottom;
|
||||
}
|
||||
@@ -1,30 +1,78 @@
|
||||
import React from 'react'
|
||||
import cx from 'classnames'
|
||||
import styles from './ArticleGridLayout.module.scss'
|
||||
import styled from 'styled-components'
|
||||
import { Box, themeGet } from '@primer/components'
|
||||
|
||||
type Props = {
|
||||
head?: React.ReactNode
|
||||
intro?: React.ReactNode
|
||||
topperSidebar?: React.ReactNode
|
||||
topper?: React.ReactNode
|
||||
toc?: React.ReactNode
|
||||
children?: React.ReactNode
|
||||
className?: string
|
||||
}
|
||||
export const ArticleGridLayout = ({ head, toc, children, className }: Props) => {
|
||||
export const ArticleGridLayout = ({
|
||||
intro,
|
||||
topperSidebar,
|
||||
topper,
|
||||
toc,
|
||||
children,
|
||||
className,
|
||||
}: Props) => {
|
||||
return (
|
||||
<div className={cx(styles.container, className)}>
|
||||
{/* head */}
|
||||
{head && <div className={styles.head}>{head}</div>}
|
||||
|
||||
{/* toc */}
|
||||
<Container className={className}>
|
||||
{topper && <Box gridArea="topper">{topper}</Box>}
|
||||
{topperSidebar && <Box gridArea="topper-sidebar">{topperSidebar}</Box>}
|
||||
{toc && (
|
||||
<div className={cx(styles.sidebar, 'border-bottom border-xl-0 pb-4 mb-5 pb-xl-0 mb-xl-0')}>
|
||||
<div className={styles.sidebarContent}>{toc}</div>
|
||||
</div>
|
||||
<SidebarContent
|
||||
gridArea="sidebar"
|
||||
alignSelf="flex-start"
|
||||
className="border-bottom border-xl-0 pb-4 mb-5 pb-xl-0 mb-xl-0"
|
||||
>
|
||||
{toc}
|
||||
</SidebarContent>
|
||||
)}
|
||||
|
||||
{/* content */}
|
||||
<div data-search="article-body" className={styles.content}>
|
||||
{intro && <Box gridArea="intro">{intro}</Box>}
|
||||
|
||||
<Box gridArea="content" data-search="article-body">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
const Container = styled(Box)`
|
||||
max-width: 720px;
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
'topper'
|
||||
'topper-sidebar'
|
||||
'intro'
|
||||
'sidebar'
|
||||
'content';
|
||||
|
||||
row-gap: ${themeGet('space.2')};
|
||||
|
||||
@media (min-width: ${themeGet('breakpoints.3')}) {
|
||||
max-width: none;
|
||||
grid-template-rows: auto 1fr;
|
||||
grid-template-columns: minmax(500px, 720px) minmax(220px, 1fr);
|
||||
grid-template-areas:
|
||||
'topper topper-sidebar'
|
||||
'intro sidebar'
|
||||
'content sidebar';
|
||||
column-gap: ${themeGet('space.9')};
|
||||
row-gap: 0;
|
||||
}
|
||||
`
|
||||
|
||||
const SidebarContent = styled(Box)`
|
||||
@media (min-width: ${themeGet('breakpoints.3')}) {
|
||||
position: sticky;
|
||||
padding-top: ${themeGet('space.4')};
|
||||
top: 0;
|
||||
max-height: calc(100vh - ${themeGet('space.4')});
|
||||
overflow-y: auto;
|
||||
padding-bottom: ${themeGet('space.4')};
|
||||
}
|
||||
`
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import cx from 'classnames'
|
||||
import { Heading } from '@primer/components'
|
||||
|
||||
import { ZapIcon, InfoIcon } from '@primer/octicons-react'
|
||||
import { Callout } from 'components/ui/Callout'
|
||||
|
||||
import { Link } from 'components/Link'
|
||||
import { DefaultLayout } from 'components/DefaultLayout'
|
||||
import { ArticleTopper } from 'components/article/ArticleTopper'
|
||||
import { ArticleTitle } from 'components/article/ArticleTitle'
|
||||
import { useArticleContext } from 'components/context/ArticleContext'
|
||||
import { useTranslation } from 'components/hooks/useTranslation'
|
||||
@@ -14,6 +14,8 @@ import { LearningTrackNav } from './LearningTrackNav'
|
||||
import { MarkdownContent } from 'components/ui/MarkdownContent'
|
||||
import { Lead } from 'components/ui/Lead'
|
||||
import { ArticleGridLayout } from './ArticleGridLayout'
|
||||
import { VersionPicker } from 'components/VersionPicker'
|
||||
import { Breadcrumbs } from 'components/Breadcrumbs'
|
||||
|
||||
// Mapping of a "normal" article to it's interactive counterpart
|
||||
const interactiveAlternatives: Record<string, { href: string }> = {
|
||||
@@ -44,12 +46,11 @@ export const ArticlePage = () => {
|
||||
|
||||
return (
|
||||
<DefaultLayout>
|
||||
<div className="container-xl px-3 px-md-6 my-4 my-lg-4">
|
||||
<ArticleTopper />
|
||||
|
||||
<div className="container-xl px-3 px-md-6 my-4">
|
||||
<ArticleGridLayout
|
||||
className="mt-7"
|
||||
head={
|
||||
topper={<Breadcrumbs />}
|
||||
topperSidebar={<VersionPicker />}
|
||||
intro={
|
||||
<>
|
||||
<ArticleTitle>{title}</ArticleTitle>
|
||||
|
||||
@@ -124,11 +125,11 @@ export const ArticlePage = () => {
|
||||
)}
|
||||
{miniTocItems.length > 1 && (
|
||||
<>
|
||||
<h2 id="in-this-article" className="f5 mb-2">
|
||||
<Heading as="h2" fontSize={1} id="in-this-article" className="mb-1">
|
||||
<a className="Link--primary" href="#in-this-article">
|
||||
{t('miniToc')}
|
||||
</a>
|
||||
</h2>
|
||||
</Heading>
|
||||
<ul className="list-style-none pl-0 f5 mb-0">
|
||||
{miniTocItems.map((item) => {
|
||||
return (
|
||||
|
||||
@@ -4,7 +4,7 @@ type Props = {
|
||||
export const ArticleTitle = ({ children }: Props) => {
|
||||
return (
|
||||
<div className="d-flex flex-items-baseline flex-justify-between">
|
||||
<h1 className="my-4 border-bottom-0">{children}</h1>
|
||||
<h1 className="mt-4 border-bottom-0">{children}</h1>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import { Breadcrumbs } from 'components/Breadcrumbs'
|
||||
import { ArticleVersionPicker } from 'components/article/ArticleVersionPicker'
|
||||
|
||||
export const ArticleTopper = () => {
|
||||
return (
|
||||
<div className="d-lg-flex flex-justify-between">
|
||||
<div className="d-block d-lg-none mb-2">
|
||||
<ArticleVersionPicker />
|
||||
</div>
|
||||
<div className="d-flex flex-items-center">
|
||||
<Breadcrumbs />
|
||||
</div>
|
||||
<div className="d-none d-lg-block">
|
||||
<ArticleVersionPicker />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import { Dropdown } from '@primer/components'
|
||||
|
||||
import { Link } from 'components/Link'
|
||||
import { useMainContext } from 'components/context/MainContext'
|
||||
import { useVersion } from 'components/hooks/useVersion'
|
||||
import { useTranslation } from 'components/hooks/useTranslation'
|
||||
|
||||
export const ArticleVersionPicker = () => {
|
||||
const router = useRouter()
|
||||
const { currentVersion } = useVersion()
|
||||
const { allVersions, page, enterpriseServerVersions } = useMainContext()
|
||||
const { t } = useTranslation('pages')
|
||||
|
||||
if (page.permalinks && page.permalinks.length <= 1) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
css={`
|
||||
ul {
|
||||
width: unset;
|
||||
}
|
||||
`}
|
||||
data-testid="article-version-picker"
|
||||
>
|
||||
<summary className="btn btn-outline p-2 outline-none">
|
||||
<span className="d-md-none d-xl-inline-block">{t('article_version')}</span>{' '}
|
||||
{allVersions[currentVersion].versionTitle}
|
||||
<Dropdown.Caret />
|
||||
</summary>
|
||||
<Dropdown.Menu direction="sw">
|
||||
{(page.permalinks || []).map((permalink) => {
|
||||
return (
|
||||
<Dropdown.Item key={permalink.href}>
|
||||
<Link href={permalink.href}>{permalink.pageVersionTitle}</Link>
|
||||
</Dropdown.Item>
|
||||
)
|
||||
})}
|
||||
<div className="pb-1">
|
||||
<Link
|
||||
href={`/${router.locale}/${enterpriseServerVersions[0]}/admin/all-releases`}
|
||||
className="f6 no-underline color-text-tertiary pl-3 pr-2 no-wrap"
|
||||
>
|
||||
See all Enterprise releases
|
||||
</Link>
|
||||
</div>
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
)
|
||||
}
|
||||
@@ -6,7 +6,7 @@ type Props = {
|
||||
}
|
||||
export function LearningTrackNav({ track }: Props) {
|
||||
const { t } = useTranslation('learning_track_nav')
|
||||
const { prevGuide, nextGuide, trackName } = track
|
||||
const { prevGuide, nextGuide, trackName, trackProduct } = track
|
||||
return (
|
||||
<div
|
||||
data-testid="learning-track-nav"
|
||||
@@ -17,7 +17,7 @@ export function LearningTrackNav({ track }: Props) {
|
||||
<>
|
||||
<span className="f6 color-text-secondary">{t('prevGuide')}</span>
|
||||
<a
|
||||
href={`${prevGuide.href}?learn=${trackName}`}
|
||||
href={`${prevGuide.href}?learn=${trackName}&learnProduct=${trackProduct}`}
|
||||
className="text-bold color-text-secondary"
|
||||
>
|
||||
{prevGuide.title}
|
||||
@@ -31,7 +31,7 @@ export function LearningTrackNav({ track }: Props) {
|
||||
<>
|
||||
<span className="f6 color-text-secondary">{t('nextGuide')}</span>
|
||||
<a
|
||||
href={`${nextGuide.href}?learn=${trackName}`}
|
||||
href={`${nextGuide.href}?learn=${trackName}&learnProduct=${trackProduct}`}
|
||||
className="text-bold color-text-secondary text-right f4"
|
||||
>
|
||||
{nextGuide.title}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createContext, useContext } from 'react'
|
||||
|
||||
export type LearningTrack = {
|
||||
trackName?: string
|
||||
trackProduct?: string
|
||||
prevGuide?: { href: string; title: string }
|
||||
nextGuide?: { href: string; title: string }
|
||||
}
|
||||
|
||||
@@ -62,10 +62,6 @@ export type MainContextT = {
|
||||
article?: BreadcrumbT
|
||||
}
|
||||
activeProducts: Array<ProductT>
|
||||
community_redirect: {
|
||||
name: string
|
||||
href: string
|
||||
}
|
||||
currentProduct?: ProductT
|
||||
currentLayoutName: string
|
||||
isHomepageVersion: boolean
|
||||
@@ -114,7 +110,6 @@ export const getMainContext = (req: any, res: any): MainContextT => {
|
||||
return {
|
||||
breadcrumbs: req.context.breadcrumbs || {},
|
||||
activeProducts: req.context.activeProducts,
|
||||
community_redirect: req.context.page?.community_redirect || {},
|
||||
currentProduct: req.context.productMap[req.context.currentProduct] || null,
|
||||
currentLayoutName: req.context.currentLayoutName,
|
||||
isHomepageVersion: req.context.page?.documentType === 'homepage',
|
||||
|
||||
@@ -3,6 +3,7 @@ import pick from 'lodash/pick'
|
||||
|
||||
export type FeaturedTrack = {
|
||||
trackName: string
|
||||
trackProduct: string
|
||||
title: string
|
||||
description: string
|
||||
guides?: Array<{ href: string; page?: { type: string }; title: string; intro: string }>
|
||||
@@ -47,14 +48,14 @@ export const getProductSubLandingContextFromRequest = (req: any): ProductSubLand
|
||||
title: req.context.productMap[req.context.currentProduct].name,
|
||||
featuredTrack: page.featuredTrack
|
||||
? {
|
||||
...pick(page.featuredTrack, ['title', 'description', 'trackName']),
|
||||
...pick(page.featuredTrack, ['title', 'description', 'trackName', 'trackProduct']),
|
||||
guides: (page.featuredTrack?.guides || []).map((guide: any) => {
|
||||
return pick(guide, ['title', 'intro', 'href', 'page.type'])
|
||||
}),
|
||||
}
|
||||
: null,
|
||||
learningTracks: (page.learningTracks || []).map((track: any) => ({
|
||||
...pick(track, ['title', 'description', 'trackName']),
|
||||
...pick(track, ['title', 'description', 'trackName', 'trackProduct']),
|
||||
guides: (track.guides || []).map((guide: any) => {
|
||||
return pick(guide, ['title', 'intro', 'href', 'page.type'])
|
||||
}),
|
||||
|
||||
@@ -38,7 +38,6 @@ export const useTocLandingContext = (): TocLandingContextT => {
|
||||
}
|
||||
|
||||
export const getTocLandingContextFromRequest = (req: any): TocLandingContextT => {
|
||||
const isEarlyAccess = req.context.page?.documentType === 'early-access'
|
||||
return {
|
||||
title: req.context.page.titlePlainText,
|
||||
productCallout: req.context.page.product || '',
|
||||
@@ -49,7 +48,7 @@ export const getTocLandingContextFromRequest = (req: any): TocLandingContextT =>
|
||||
variant: req.context.genericTocFlat ? 'expanded' : 'compact',
|
||||
|
||||
featuredLinks: getFeaturedLinksFromReq(req),
|
||||
renderedPage: isEarlyAccess ? req.context.renderedPage : '',
|
||||
renderedPage: req.context.renderedPage,
|
||||
currentLearningTrack: req.context.currentLearningTrack,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
import cx from 'classnames'
|
||||
import { useRouter } from 'next/router'
|
||||
import { Dropdown, Details, useDetails } from '@primer/components'
|
||||
import { ChevronDownIcon } from '@primer/octicons-react'
|
||||
|
||||
import { Link } from 'components/Link'
|
||||
import { useMainContext } from 'components/context/MainContext'
|
||||
import { useVersion } from 'components/hooks/useVersion'
|
||||
|
||||
type Props = {
|
||||
variant?: 'inline'
|
||||
}
|
||||
export const HomepageVersionPicker = ({ variant }: Props) => {
|
||||
const router = useRouter()
|
||||
const { currentVersion } = useVersion()
|
||||
const { getDetailsProps } = useDetails({})
|
||||
const { allVersions, page, enterpriseServerVersions } = useMainContext()
|
||||
|
||||
if (page.permalinks && page.permalinks.length <= 1) {
|
||||
return null
|
||||
}
|
||||
|
||||
const label = allVersions[currentVersion].versionTitle
|
||||
|
||||
if (variant === 'inline') {
|
||||
return (
|
||||
<Details {...getDetailsProps()} className="details-reset">
|
||||
<summary className="outline-none" aria-label="Toggle language list">
|
||||
<div className="d-flex flex-items-center flex-justify-between py-2">
|
||||
<span>{label}</span>
|
||||
<ChevronDownIcon size={24} className="arrow ml-md-1" />
|
||||
</div>
|
||||
</summary>
|
||||
<div>
|
||||
{(page.permalinks || []).map((permalink) => {
|
||||
return (
|
||||
<Link
|
||||
key={permalink.href}
|
||||
href={permalink.href}
|
||||
className={cx(
|
||||
'd-block py-2',
|
||||
permalink.href === router.asPath
|
||||
? 'color-text-link text-underline active'
|
||||
: 'Link--primary no-underline'
|
||||
)}
|
||||
>
|
||||
{permalink.pageVersionTitle}
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
<Link
|
||||
href={`/${router.locale}/${enterpriseServerVersions[0]}/admin/all-releases`}
|
||||
className="f6 no-underline color-text-tertiary no-wrap"
|
||||
>
|
||||
See all Enterprise releases
|
||||
</Link>
|
||||
</div>
|
||||
</Details>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
css={`
|
||||
ul {
|
||||
width: unset;
|
||||
}
|
||||
`}
|
||||
>
|
||||
<summary>
|
||||
{label}
|
||||
<Dropdown.Caret />
|
||||
</summary>
|
||||
<Dropdown.Menu direction="sw">
|
||||
{(page.permalinks || []).map((permalink) => {
|
||||
return (
|
||||
<Dropdown.Item key={permalink.href}>
|
||||
<Link href={permalink.href}>{permalink.pageVersionTitle}</Link>
|
||||
</Dropdown.Item>
|
||||
)
|
||||
})}
|
||||
<div className="pb-1">
|
||||
<Link
|
||||
href={`/${router.locale}/${enterpriseServerVersions[0]}/admin/all-releases`}
|
||||
className="f6 no-underline color-text-tertiary pl-3 pr-2 no-wrap"
|
||||
>
|
||||
See all Enterprise releases
|
||||
</Link>
|
||||
</div>
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
)
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
import { DefaultLayout } from 'components/DefaultLayout'
|
||||
import { TableOfContents } from 'components/landing/TableOfContents'
|
||||
import { useTocLandingContext } from 'components/context/TocLandingContext'
|
||||
import { ArticleTopper } from 'components/article/ArticleTopper'
|
||||
import { VersionPicker } from 'components/VersionPicker'
|
||||
import { Breadcrumbs } from 'components/Breadcrumbs'
|
||||
import { ArticleTitle } from 'components/article/ArticleTitle'
|
||||
import { MarkdownContent } from 'components/ui/MarkdownContent'
|
||||
import { ArticleList } from 'components/landing/ArticleList'
|
||||
@@ -9,7 +10,7 @@ import { useTranslation } from 'components/hooks/useTranslation'
|
||||
import { ArticleGridLayout } from 'components/article/ArticleGridLayout'
|
||||
import { Callout } from 'components/ui/Callout'
|
||||
import { Lead } from 'components/ui/Lead'
|
||||
import { LearningTrackNav } from '../article/LearningTrackNav'
|
||||
import { LearningTrackNav } from 'components/article/LearningTrackNav'
|
||||
|
||||
export const TocLanding = () => {
|
||||
const {
|
||||
@@ -26,10 +27,8 @@ export const TocLanding = () => {
|
||||
|
||||
return (
|
||||
<DefaultLayout>
|
||||
<div className="container-xl px-3 px-md-6 my-4 my-lg-4">
|
||||
<ArticleTopper />
|
||||
|
||||
<ArticleGridLayout className="mt-7">
|
||||
<div className="container-xl px-3 px-md-6 my-4">
|
||||
<ArticleGridLayout topper={<Breadcrumbs />} topperSidebar={<VersionPicker />}>
|
||||
<ArticleTitle>{title}</ArticleTitle>
|
||||
|
||||
{introPlainText && <Lead>{introPlainText}</Lead>}
|
||||
@@ -59,7 +58,7 @@ export const TocLanding = () => {
|
||||
)}
|
||||
|
||||
{renderedPage && (
|
||||
<div id="article-contents">
|
||||
<div id="article-contents" className="mb-5">
|
||||
<MarkdownContent>{renderedPage}</MarkdownContent>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -7,18 +7,29 @@ import { useMainContext } from 'components/context/MainContext'
|
||||
export const Support = () => {
|
||||
const { isEnterprise } = useVersion()
|
||||
const { t } = useTranslation('support')
|
||||
const { community_redirect } = useMainContext()
|
||||
const { relativePath } = useMainContext()
|
||||
|
||||
let updatedCommunityLink = ''
|
||||
|
||||
if (
|
||||
relativePath?.startsWith('codespaces') ||
|
||||
relativePath?.startsWith('discussions') ||
|
||||
relativePath?.startsWith('sponsors')
|
||||
) {
|
||||
const product = relativePath.substring(0, relativePath.indexOf('/'))
|
||||
updatedCommunityLink = `https://github.com/github/feedback/discussions/categories/${product}-feedback`
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3 className="mb-2 f4">{t`still_need_help`}</h3>
|
||||
<a
|
||||
id="ask-community"
|
||||
href={community_redirect.href || 'https://github.community/'}
|
||||
href={updatedCommunityLink === '' ? 'https://github.community/' : updatedCommunityLink}
|
||||
className="btn btn-outline mr-4 mt-2"
|
||||
>
|
||||
<PeopleIcon size="small" className="octicon mr-1" />
|
||||
{Object.keys(community_redirect).length === 0 ? t`ask_community` : community_redirect.name}
|
||||
{updatedCommunityLink === '' ? t`ask_community` : 'Provide GitHub Feedback'}
|
||||
</a>
|
||||
<a
|
||||
id="contact-us"
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useState } from 'react'
|
||||
import cx from 'classnames'
|
||||
import { useRouter } from 'next/router'
|
||||
import { MarkGithubIcon, ThreeBarsIcon, XIcon } from '@primer/octicons-react'
|
||||
import { ButtonOutline } from '@primer/components'
|
||||
|
||||
import { Link } from 'components/Link'
|
||||
import { useMainContext } from 'components/context/MainContext'
|
||||
@@ -10,8 +9,8 @@ import { LanguagePicker } from './LanguagePicker'
|
||||
import { HeaderNotifications } from 'components/page-header/HeaderNotifications'
|
||||
import { ProductPicker } from 'components/page-header/ProductPicker'
|
||||
import { useTranslation } from 'components/hooks/useTranslation'
|
||||
import { HomepageVersionPicker } from 'components/landing/HomepageVersionPicker'
|
||||
import { Search } from 'components/Search'
|
||||
import { VersionPicker } from 'components/VersionPicker'
|
||||
|
||||
export const Header = () => {
|
||||
const router = useRouter()
|
||||
@@ -31,25 +30,23 @@ export const Header = () => {
|
||||
<div className="border-bottom color-border-secondary no-print">
|
||||
{error !== '404' && <HeaderNotifications />}
|
||||
|
||||
<header
|
||||
className="container-xl px-3 px-md-6 pt-3 pb-3 position-relative"
|
||||
style={{ zIndex: 2 }}
|
||||
>
|
||||
<header className={cx('container-xl px-3 px-md-6 pt-3 pb-3 position-relative z-3')}>
|
||||
{/* desktop header */}
|
||||
<div className="d-none d-lg-flex flex-justify-end" data-testid="desktop-header">
|
||||
<div
|
||||
className="d-none d-lg-flex flex-justify-end flex-items-center"
|
||||
data-testid="desktop-header"
|
||||
>
|
||||
{showVersionPicker && (
|
||||
<div className="py-2 mr-4">
|
||||
<HomepageVersionPicker />
|
||||
<div className="mr-2">
|
||||
<VersionPicker hideLabel={true} variant="compact" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="py-2">
|
||||
<LanguagePicker />
|
||||
</div>
|
||||
<LanguagePicker />
|
||||
|
||||
{/* <!-- GitHub.com homepage and 404 page has a stylized search; Enterprise homepages do not --> */}
|
||||
{relativePath !== 'index.md' && error !== '404' && (
|
||||
<div className="d-inline-block ml-4">
|
||||
<div className="d-inline-block ml-3">
|
||||
<Search updateSearchParams={updateSearchParams} isOverlay={true} />
|
||||
</div>
|
||||
)}
|
||||
@@ -72,14 +69,14 @@ export const Header = () => {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<ButtonOutline
|
||||
<button
|
||||
className="btn"
|
||||
data-testid="mobile-menu-button"
|
||||
css
|
||||
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
||||
aria-label="Navigation Menu"
|
||||
>
|
||||
{isMenuOpen ? <XIcon size="small" /> : <ThreeBarsIcon size="small" />}
|
||||
</ButtonOutline>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -87,31 +84,33 @@ export const Header = () => {
|
||||
<div className="relative">
|
||||
<div
|
||||
className={cx(
|
||||
'width-full position-absolute left-0 right-0 color-shadow-large color-bg-primary px-3 px-md-6 pb-3',
|
||||
'width-full position-absolute left-0 right-0 color-shadow-large color-bg-primary px-2 px-md-4 pb-3',
|
||||
isMenuOpen ? 'd-block' : 'd-none'
|
||||
)}
|
||||
>
|
||||
<div className="mt-3 mb-2">
|
||||
<h4 className="f5 text-normal color-text-secondary">{t('explore_by_product')}</h4>
|
||||
<h4 className="f5 text-normal color-text-secondary ml-3">
|
||||
{t('explore_by_product')}
|
||||
</h4>
|
||||
|
||||
<ProductPicker />
|
||||
</div>
|
||||
|
||||
{/* <!-- Versions picker that only appears in the header on landing pages --> */}
|
||||
{showVersionPicker && (
|
||||
<div className="border-top py-2">
|
||||
<HomepageVersionPicker variant="inline" />
|
||||
</div>
|
||||
<>
|
||||
<div className="border-top my-2 mx-3" />
|
||||
<VersionPicker hideLabel={true} variant="inline" popoverVariant={'inline'} />
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* <!-- Language picker - 'English', 'Japanese', etc --> */}
|
||||
<div className="border-top py-2">
|
||||
<LanguagePicker variant="inline" />
|
||||
</div>
|
||||
<div className="border-top my-2 mx-3" />
|
||||
<LanguagePicker variant="inline" />
|
||||
|
||||
{/* <!-- GitHub.com homepage and 404 page has a stylized search; Enterprise homepages do not --> */}
|
||||
{relativePath !== 'index.md' && error !== '404' && (
|
||||
<div className="pt-3 border-top">
|
||||
<div className="my-2 pt-3 mx-3">
|
||||
<Search updateSearchParams={updateSearchParams} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import cx from 'classnames'
|
||||
import { useRouter } from 'next/router'
|
||||
import { Dropdown, Details, useDetails } from '@primer/components'
|
||||
import { Box, Dropdown, Details, Text, useDetails } from '@primer/components'
|
||||
import { ChevronDownIcon } from '@primer/octicons-react'
|
||||
|
||||
import { Link } from 'components/Link'
|
||||
@@ -12,76 +11,63 @@ type Props = {
|
||||
export const LanguagePicker = ({ variant }: Props) => {
|
||||
const router = useRouter()
|
||||
const { languages } = useLanguages()
|
||||
const { getDetailsProps } = useDetails({})
|
||||
const { getDetailsProps, setOpen } = useDetails({ closeOnOutsideClick: true })
|
||||
const locale = router.locale || 'en'
|
||||
const langs = Object.values(languages)
|
||||
const selectedLang = languages[locale]
|
||||
|
||||
if (variant === 'inline') {
|
||||
return (
|
||||
<Details {...getDetailsProps()} className="details-reset">
|
||||
<summary className="outline-none" aria-label="Toggle language list">
|
||||
<div className="d-flex flex-items-center flex-justify-between py-2">
|
||||
<span>{selectedLang.nativeName || selectedLang.name}</span>
|
||||
<Details {...getDetailsProps()} data-testid="language-picker">
|
||||
<summary
|
||||
className="d-block btn btn-invisible color-text-primary"
|
||||
aria-label="Toggle language list"
|
||||
>
|
||||
<div className="d-flex flex-items-center flex-justify-between">
|
||||
<Text>{selectedLang.nativeName || selectedLang.name}</Text>
|
||||
<ChevronDownIcon size={24} className="arrow ml-md-1" />
|
||||
</div>
|
||||
</summary>
|
||||
<div>
|
||||
<Box mt={1}>
|
||||
{langs.map((lang) => {
|
||||
if (lang.wip) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Link
|
||||
key={lang.code}
|
||||
href={router.asPath}
|
||||
locale={lang.code}
|
||||
disableClientTransition={true}
|
||||
className={cx(
|
||||
'd-block py-2',
|
||||
lang.code === router.locale
|
||||
? 'color-text-link text-underline active'
|
||||
: 'Link--primary no-underline'
|
||||
)}
|
||||
>
|
||||
{lang.nativeName ? (
|
||||
<>
|
||||
{lang.nativeName} ({lang.name})
|
||||
</>
|
||||
) : (
|
||||
lang.name
|
||||
)}
|
||||
</Link>
|
||||
<Dropdown.Item onClick={() => setOpen(false)} key={lang.code}>
|
||||
<Link href={router.asPath} locale={lang.code}>
|
||||
{lang.nativeName ? (
|
||||
<>
|
||||
{lang.nativeName} ({lang.name})
|
||||
</>
|
||||
) : (
|
||||
lang.name
|
||||
)}
|
||||
</Link>
|
||||
</Dropdown.Item>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</Box>
|
||||
</Details>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
css={`
|
||||
ul {
|
||||
width: unset;
|
||||
}
|
||||
`}
|
||||
data-testid="language-picker"
|
||||
>
|
||||
<summary>
|
||||
{selectedLang.nativeName || selectedLang.name}
|
||||
<Details {...getDetailsProps()} data-testid="language-picker" className="position-relative">
|
||||
<summary className="d-block btn btn-invisible color-text-primary">
|
||||
<Text>{selectedLang.nativeName || selectedLang.name}</Text>
|
||||
<Dropdown.Caret />
|
||||
</summary>
|
||||
<Dropdown.Menu direction="sw">
|
||||
<Dropdown.Menu direction="sw" style={{ width: 'unset' }}>
|
||||
{langs.map((lang) => {
|
||||
if (lang.wip) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Dropdown.Item key={lang.code}>
|
||||
<Link href={router.asPath} locale={lang.code} disableClientTransition={true}>
|
||||
<Dropdown.Item key={lang.code} onClick={() => setOpen(false)}>
|
||||
<Link href={router.asPath} locale={lang.code}>
|
||||
{lang.nativeName ? (
|
||||
<>
|
||||
{lang.nativeName} ({lang.name})
|
||||
@@ -94,6 +80,6 @@ export const LanguagePicker = ({ variant }: Props) => {
|
||||
)
|
||||
})}
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
</Details>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,53 +1,48 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import cx from 'classnames'
|
||||
|
||||
import { Link } from 'components/Link'
|
||||
import { useMainContext } from 'components/context/MainContext'
|
||||
import { ChevronDownIcon, LinkExternalIcon } from '@primer/octicons-react'
|
||||
import { Details, useDetails } from '@primer/components'
|
||||
import { Box, Dropdown, Details, useDetails } from '@primer/components'
|
||||
|
||||
// Product Picker - GitHub.com, Enterprise Server, etc
|
||||
export const ProductPicker = () => {
|
||||
const router = useRouter()
|
||||
const { activeProducts, currentProduct } = useMainContext()
|
||||
const { getDetailsProps } = useDetails({})
|
||||
const { getDetailsProps, setOpen } = useDetails({ closeOnOutsideClick: true })
|
||||
|
||||
return (
|
||||
<Details {...getDetailsProps()} className="details-reset">
|
||||
<summary
|
||||
className="color-text-link outline-none"
|
||||
className="d-block color-text-primary btn btn-invisible"
|
||||
role="button"
|
||||
aria-label="Toggle products list"
|
||||
>
|
||||
<div id="current-product" className="d-flex flex-items-center flex-justify-between py-2">
|
||||
{/* <!-- Product switcher - GitHub.com, Enterprise Server, etc -->
|
||||
<!-- 404 and 500 error layouts are not real pages so we need to hardcode the name for those --> */}
|
||||
<div
|
||||
data-testid="current-product"
|
||||
data-current-product-path={currentProduct?.href}
|
||||
className="d-flex flex-items-center flex-justify-between"
|
||||
>
|
||||
<span>{currentProduct?.name || 'All Products'}</span>
|
||||
<ChevronDownIcon size={24} className="arrow ml-md-1" />
|
||||
</div>
|
||||
</summary>
|
||||
<div id="homepages" style={{ zIndex: 6 }}>
|
||||
<Box data-testid="product-picker-list" py="2" style={{ zIndex: 6 }}>
|
||||
{activeProducts.map((product) => {
|
||||
return (
|
||||
<Link
|
||||
key={product.id}
|
||||
href={`${product.external ? '' : `/${router.locale}`}${product.href}`}
|
||||
className={cx(
|
||||
'd-block py-2',
|
||||
product.id === currentProduct?.id
|
||||
? 'color-text-link text-underline active'
|
||||
: 'Link--primary no-underline'
|
||||
)}
|
||||
>
|
||||
{product.name}
|
||||
{product.external && (
|
||||
<span className="ml-1">
|
||||
<LinkExternalIcon size="small" />
|
||||
</span>
|
||||
)}
|
||||
</Link>
|
||||
<Dropdown.Item key={product.id} onClick={() => setOpen(false)}>
|
||||
<Link href={`${product.external ? '' : `/${router.locale}`}${product.href}`}>
|
||||
{product.name}
|
||||
{product.external && (
|
||||
<span className="ml-1">
|
||||
<LinkExternalIcon size="small" />
|
||||
</span>
|
||||
)}
|
||||
</Link>
|
||||
</Dropdown.Item>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</Box>
|
||||
</Details>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -31,17 +31,16 @@ export const CodeLanguagePicker = ({ variant }: Props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<SelectMenu css className="position-relative">
|
||||
<Button as="summary" css>
|
||||
<SelectMenu className="position-relative">
|
||||
<Button as="summary">
|
||||
{currentLanguage.label} <Dropdown.Caret />
|
||||
</Button>
|
||||
<SelectMenu.Modal css style={{ minWidth: 300 }} align="right">
|
||||
<SelectMenu.Header css>Programming Language</SelectMenu.Header>
|
||||
<SelectMenu.Modal style={{ minWidth: 300 }} align="right">
|
||||
<SelectMenu.Header>Programming Language</SelectMenu.Header>
|
||||
<SelectMenu.List>
|
||||
{codeLanguages.map((language) => (
|
||||
<SelectMenu.Item
|
||||
key={language.id}
|
||||
css
|
||||
as="a"
|
||||
href={`${routePath}?langId=${language.id}`}
|
||||
selected={language.id === currentLanguage.id}
|
||||
|
||||
@@ -33,7 +33,9 @@ export const LearningTrack = ({ track }: Props) => {
|
||||
<a
|
||||
className="d-inline-flex btn no-wrap mt-3 mt-md-0 flex-items-center flex-justify-center"
|
||||
role="button"
|
||||
href={`${track?.guides && track?.guides[0].href}?learn=${track?.trackName}`}
|
||||
href={`${track?.guides && track?.guides[0].href}?learn=${
|
||||
track?.trackName
|
||||
}&learnProduct=${track?.trackProduct}`}
|
||||
>
|
||||
<span>{t('start')}</span>
|
||||
<ArrowRightIcon size={20} className="ml-2" />
|
||||
@@ -44,7 +46,7 @@ export const LearningTrack = ({ track }: Props) => {
|
||||
<div key={guide.href + track?.trackName}>
|
||||
<a
|
||||
className="Box-row d-flex flex-items-center color-text-primary no-underline"
|
||||
href={`${guide.href}?learn=${track?.trackName}`}
|
||||
href={`${guide.href}?learn=${track?.trackName}&learnProduct=${track?.trackProduct}`}
|
||||
>
|
||||
<div
|
||||
className="color-bg-tertiary d-inline-flex mr-4 circle flex-items-center flex-justify-center"
|
||||
|
||||
@@ -16,7 +16,7 @@ export const SubLandingHero = () => {
|
||||
const guideItems = featuredTrack?.guides?.map((guide) => (
|
||||
<li className="px-2 d-flex flex-shrink-0" key={guide.href} style={{ width: cardWidth }}>
|
||||
<Link
|
||||
href={`${guide.href}?learn=${featuredTrack.trackName}`}
|
||||
href={`${guide.href}?learn=${featuredTrack.trackName}&learnProduct=${featuredTrack.trackProduct}`}
|
||||
className="d-inline-block Box p-5 color-bg-primary color-border-primary no-underline"
|
||||
>
|
||||
<div className="d-flex flex-justify-between flex-items-center">
|
||||
@@ -71,7 +71,7 @@ export const SubLandingHero = () => {
|
||||
<Link
|
||||
className="d-inline-flex flex-items-center flex-justify-center btn px-4 py-2 f5 no-underline text-bold"
|
||||
role="button"
|
||||
href={`${featuredTrack.guides[0].href}?learn=${featuredTrack.trackName}`}
|
||||
href={`${featuredTrack.guides[0].href}?learn=${featuredTrack.trackName}&learnProduct=${featuredTrack.trackProduct}`}
|
||||
>
|
||||
{t(`start_path`)}
|
||||
<ArrowRightIcon size={20} className="ml-2" />
|
||||
|
||||
@@ -78,6 +78,7 @@ The `github` context contains information about the workflow run and the event t
|
||||
| `github.repository_owner` | `string` | The repository owner's name. For example, `Codertocat`. |
|
||||
| `github.run_id` | `string` | {% data reusables.github-actions.run_id_description %} |
|
||||
| `github.run_number` | `string` | {% data reusables.github-actions.run_number_description %} |
|
||||
| `github.run_attempt` | `string` | A unique number for each attempt of a particular workflow run in a repository. This number begins at 1 for the workflow run's first attempt, and increments with each re-run. |
|
||||
| `github.server_url` | `string` | Returns the URL of the GitHub server. For example: `https://github.com`. |
|
||||
| `github.sha` | `string` | The commit SHA that triggered the workflow run. |
|
||||
| `github.token` | `string` | A token to authenticate on behalf of the GitHub App installed on your repository. This is functionally equivalent to the `GITHUB_TOKEN` secret. For more information, see "[Authenticating with the GITHUB_TOKEN](/actions/automating-your-workflow-with-github-actions/authenticating-with-the-github_token)." |
|
||||
|
||||
@@ -79,34 +79,6 @@ You can use a fallback number regardless of whether you've configured authentica
|
||||
|
||||
After setup, the backup device will receive a confirmation SMS.
|
||||
|
||||
## Adding a fallback authentication method with Recover Accounts Elsewhere
|
||||
|
||||
You can generate an extra authentication credential for your account and store it with a partner recovery provider.
|
||||
|
||||
### About Recover Accounts Elsewhere
|
||||
|
||||
With Recover Accounts Elsewhere, you can add an extra security factor to your {% data variables.product.product_name %} account in case you lose access to your two-factor authentication method or recovery codes.
|
||||
|
||||
Recover Accounts Elsewhere lets you associate your {% data variables.product.product_name %} account with your Facebook account. You can store an authentication credential in the form of an _account recovery token_ for your {% data variables.product.product_name %} account with Facebook.
|
||||
|
||||
If you lose access to your {% data variables.product.product_name %} account because you no longer have access to your two-factor authentication method or recovery codes, you can retrieve your account recovery token from the recovery provider to help prove that you're the owner of your {% data variables.product.product_name %} account.
|
||||
|
||||
After you retrieve your token, {% data variables.contact.contact_support %} may be able to disable two-factor authentication for your account. Then, you can provide or reset your password to regain access to your account.
|
||||
|
||||
When you generate or retrieve an account recovery token, an event is added to your account's audit log. For more information, see "[Reviewing your security log](/articles/reviewing-your-security-log)."
|
||||
|
||||
### Generating and storing an account recovery token
|
||||
|
||||
You can generate an account recovery token and store it with a partner recovery provider.
|
||||
|
||||
1. Sign in to your Facebook account, then return to {% data variables.product.product_name %}.
|
||||
{% data reusables.user_settings.access_settings %}
|
||||
{% data reusables.user_settings.security %}
|
||||
4. To generate a new token, under "Recovery tokens," click **Store new token**. 
|
||||
5. Read the information about account recovery tokens, then click **Connect with https://www.facebook.com**. 
|
||||
6. After you're redirected to Facebook, read the information about turning on account recovery with Facebook before you click **Save as [_YOUR NAME_]**. (If you save multiple tokens within a short period of time, Facebook may skip this confirmation step after you save your first token.)
|
||||

|
||||
|
||||
{% endif %}
|
||||
|
||||
## Further reading
|
||||
|
||||
@@ -78,6 +78,12 @@ You can use your two-factor authentication credentials or two-factor authenticat
|
||||
|
||||
## Authenticating with an account recovery token
|
||||
|
||||
{% warning %}
|
||||
|
||||
**Warning:** Account recovery tokens are deprecated and will be disabled on **December 1st, 2021**. Please ensure you have configured other two-factor recovery methods. For more information, see "[Configuring two-factor authentication recovery methods](/articles/configuring-two-factor-authentication-recovery-methods)."
|
||||
|
||||
{% endwarning %}
|
||||
|
||||
If you lose access to the two-factor authentication methods for your {% data variables.product.product_name %} account, you can retrieve your account recovery token from a partner recovery provider and ask {% data variables.product.prodname_dotcom %} Support to review it.
|
||||
|
||||
If you don't have access to your two-factor authentication methods or recovery codes and you've stored an account recovery token with Facebook using Recover Accounts Elsewhere, you may be able to use your token to regain access to your account.
|
||||
|
||||
@@ -24,9 +24,6 @@ featuredLinks:
|
||||
- /codespaces/setting-up-your-codespace/personalizing-codespaces-for-your-account
|
||||
popularHeading: Set up your project
|
||||
product_video: 'https://www.youtube-nocookie.com/embed/_W9B7qc9lVc'
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/codespaces-feedback'
|
||||
redirect_from:
|
||||
- /github/developing-online-with-github-codespaces
|
||||
- /github/developing-online-with-codespaces
|
||||
|
||||
@@ -26,9 +26,6 @@ changelog:
|
||||
examples_source: data/product-examples/discussions/community-examples.yml
|
||||
product_video: 'https://www.youtube-nocookie.com/embed/IpBw2SJkFyk'
|
||||
layout: product-landing
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/discussions-feedback'
|
||||
versions:
|
||||
fpt: '*'
|
||||
children:
|
||||
|
||||
@@ -277,6 +277,14 @@ The footnote will render like this:
|
||||

|
||||
{% endif %}
|
||||
|
||||
## Hiding content with comments
|
||||
|
||||
You can tell {% data variables.product.product_name %} to hide content from the rendered Markdown by placing the content in an HTML comment.
|
||||
|
||||
<pre>
|
||||
<!-- This content will not appear in the rendered Markdown -->
|
||||
</pre>
|
||||
|
||||
## Ignoring Markdown formatting
|
||||
|
||||
You can tell {% data variables.product.product_name %} to ignore (or escape) Markdown formatting by using `\` before the Markdown character.
|
||||
@@ -287,13 +295,13 @@ You can tell {% data variables.product.product_name %} to ignore (or escape) Mar
|
||||
|
||||
For more information, see Daring Fireball's "[Markdown Syntax](https://daringfireball.net/projects/markdown/syntax#backslash)."
|
||||
|
||||
## Hiding content with comments
|
||||
{% ifversion fpt or ghes > 3.2 or ghae-issue-5232 %}
|
||||
|
||||
You can tell {% data variables.product.product_name %} to hide content from the rendered Markdown by placing the content in an HTML comment.
|
||||
## Disabling Markdown rendering
|
||||
|
||||
<pre>
|
||||
<!-- This content will not appear in the rendered Markdown -->
|
||||
</pre>
|
||||
{% data reusables.repositories.disabling-markdown-rendering %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
## Further reading
|
||||
|
||||
|
||||
@@ -190,6 +190,14 @@ You can click {% octicon "file" aria-label="The paper icon" %} to see the change
|
||||
|
||||

|
||||
|
||||
{% ifversion fpt or ghes > 3.2 or ghae-issue-5232 %}
|
||||
|
||||
### Disabling Markdown rendering
|
||||
|
||||
{% data reusables.repositories.disabling-markdown-rendering %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
### Visualizing attribute changes
|
||||
|
||||
We provide a tooltip
|
||||
|
||||
@@ -34,9 +34,6 @@ children:
|
||||
- /receiving-sponsorships-through-github-sponsors
|
||||
- /integrating-with-github-sponsors
|
||||
- /guides
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/sponsors-feedback'
|
||||
---
|
||||
<!---->
|
||||
<!---->
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
access token.
|
||||
- term: account recovery token
|
||||
description: >-
|
||||
**Deprecated and will be disabled December 1st, 2021.**
|
||||
The authentication credential stored as part of an account recovery setup called Recover Accounts Elsewhere that allows you to store this backup credential.
|
||||
- term: API preview
|
||||
description: >-
|
||||
@@ -597,6 +598,7 @@
|
||||
the HEAD of that branch to the result.
|
||||
- term: Recover Accounts Elsewhere
|
||||
description: >-
|
||||
**Deprecated and will be disabled December 1st, 2021.**
|
||||
Allows users to add an extra security factor to their GitHub account in case they
|
||||
lose access to their two-factor authentication method or recovery codes.
|
||||
Users can associate their GitHub account with their Facebook account by
|
||||
|
||||
@@ -6,6 +6,7 @@ sections:
|
||||
bugs:
|
||||
- 'Resque worker counts were displayed incorrectly during maintenance mode. {% comment %} https://github.com/github/enterprise2/pull/26898, https://github.com/github/enterprise2/pull/26883 {% endcomment %}'
|
||||
- 'Allocated memcached memory could be zero in clustering mode. {% comment %} https://github.com/github/enterprise2/pull/26927, https://github.com/github/enterprise2/pull/26832 {% endcomment %}'
|
||||
- 'Fixes {% data variables.product.prodname_pages %} builds so they take into account the NO_PROXY setting of the appliance. This is relevant to appliances configured with an HTTP proxy only. (update 2021-09-30) {% comment %} https://github.com/github/pages/pull/3360 {% endcomment %}'
|
||||
known_issues:
|
||||
- On a freshly set up {% data variables.product.prodname_ghe_server %} without any users, an attacker could create the first admin user.
|
||||
- Custom firewall rules are removed during the upgrade process.
|
||||
|
||||
@@ -7,6 +7,7 @@ sections:
|
||||
- 'Resque worker counts were displayed incorrectly during maintenance mode. {% comment %} https://github.com/github/enterprise2/pull/26899, https://github.com/github/enterprise2/pull/26883 {% endcomment %}'
|
||||
- 'Allocated memcached memory could be zero in clustering mode. {% comment %} https://github.com/github/enterprise2/pull/26928, https://github.com/github/enterprise2/pull/26832 {% endcomment %}'
|
||||
- 'Non-empty binary files displayed an incorrect file type and size on the pull request "Files" tab. {% comment %} https://github.com/github/github/pull/192810, https://github.com/github/github/pull/172284, https://github.com/github/coding/issues/694 {% endcomment %}'
|
||||
- 'Fixes {% data variables.product.prodname_pages %} builds so they take into account the NO_PROXY setting of the appliance. This is relevant to appliances configured with an HTTP proxy only. (update 2021-09-30) {% comment %} https://github.com/github/pages/pull/3360 {% endcomment %}'
|
||||
known_issues:
|
||||
- The {% data variables.product.prodname_registry %} npm registry no longer returns a time value in metadata responses. This was done to allow for substantial performance improvements. We continue to have all the data necessary to return a time value as part of the metadata response and will resume returning this value in the future once we have solved the existing performance issues.
|
||||
- On a freshly set up {% data variables.product.prodname_ghe_server %} without any users, an attacker could create the first admin user.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
When viewing a Markdown file, you can click {% octicon "code" aria-label="The code icon" %} at the top of the file to disable Markdown rendering and view the file's source instead.
|
||||
|
||||

|
||||
|
||||
Disabling Markdown rendering enables you to use source view features, such as line linking, which is not possible when viewing rendered Markdown files.
|
||||
@@ -40,9 +40,10 @@ toc:
|
||||
guides: Guides
|
||||
whats_new: What's new
|
||||
pages:
|
||||
article_version: 'Article version:'
|
||||
article_version: 'Article version'
|
||||
miniToc: In this article
|
||||
contributor_callout: This article is contributed and maintained by
|
||||
all_enterprise_releases: All Enterprise releases
|
||||
errors:
|
||||
oops: Ooops!
|
||||
something_went_wrong: It looks like something went wrong.
|
||||
|
||||
@@ -149,14 +149,6 @@ export const schema = {
|
||||
interactive: {
|
||||
type: 'boolean',
|
||||
},
|
||||
// Redirect Community Support link to Public Discussions
|
||||
community_redirect: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: 'string',
|
||||
href: 'string',
|
||||
},
|
||||
},
|
||||
// Platform-specific content preference
|
||||
defaultPlatform: {
|
||||
type: 'string',
|
||||
|
||||
@@ -34,6 +34,7 @@ export default async function processLearningTracks(rawLearningTracks, context)
|
||||
|
||||
const learningTrack = {
|
||||
trackName: renderedTrackName,
|
||||
trackProduct: context.currentProduct || null,
|
||||
title: await renderContent(track.title, context, renderOpts),
|
||||
description: await renderContent(track.description, context, renderOpts),
|
||||
// getLinkData respects versioning and only returns guides available in the current version;
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -13,14 +13,24 @@ export default async function learningTrack(req, res, next) {
|
||||
const trackName = req.query.learn
|
||||
if (!trackName) return noTrack()
|
||||
|
||||
const tracksPerProduct = req.context.site.data['learning-tracks'][req.context.currentProduct]
|
||||
let trackProduct = req.context.currentProduct
|
||||
let tracksPerProduct = req.context.site.data['learning-tracks'][trackProduct]
|
||||
|
||||
// If there are no learning tracks for the current product, try and fall
|
||||
// back to the learning track product set as a URL parameter. This handles
|
||||
// the case where a learning track has guide paths for a different product
|
||||
// than the current learning track product.
|
||||
if (!tracksPerProduct) {
|
||||
trackProduct = req.query.learnProduct
|
||||
tracksPerProduct = req.context.site.data['learning-tracks'][trackProduct]
|
||||
}
|
||||
|
||||
if (!tracksPerProduct) return noTrack()
|
||||
|
||||
const track = req.context.site.data['learning-tracks'][req.context.currentProduct][trackName]
|
||||
const track = req.context.site.data['learning-tracks'][trackProduct][trackName]
|
||||
if (!track) return noTrack()
|
||||
|
||||
const currentLearningTrack = { trackName }
|
||||
|
||||
const currentLearningTrack = { trackName, trackProduct }
|
||||
const guidePath = getPathWithoutLanguage(getPathWithoutVersion(req.pagePath))
|
||||
let guideIndex = track.guides.findIndex((path) => path === guidePath)
|
||||
|
||||
|
||||
412
package-lock.json
generated
412
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@
|
||||
"dependencies": {
|
||||
"@alex_neo/jest-expect-message": "^1.0.5",
|
||||
"@hapi/accept": "^5.0.2",
|
||||
"@primer/components": "^28.5.0",
|
||||
"@primer/components": "^29.1.1",
|
||||
"@primer/css": "^17.9.0",
|
||||
"@primer/octicons": "^15.1.0",
|
||||
"@primer/octicons-react": "^15.1.0",
|
||||
@@ -214,7 +214,7 @@
|
||||
"prevent-pushes-to-main": "node script/prevent-pushes-to-main.js",
|
||||
"rest-dev": "script/rest/update-files.js && npm run dev",
|
||||
"start": "run-script-os",
|
||||
"start:win32": "cross-env NODE_ENV=development ENABLED_LANGUAGES='en,ja' --signal SIGKILL nodemon server.mjs",
|
||||
"start:win32": "cross-env NODE_ENV=development ENABLED_LANGUAGES='en,ja' nodemon --signal SIGKILL server.mjs",
|
||||
"start:default": "cross-env NODE_ENV=development ENABLED_LANGUAGES='en,ja' nodemon server.mjs",
|
||||
"start-all-languages": "cross-env NODE_ENV=development nodemon server.mjs",
|
||||
"sync-search": "start-server-and-test sync-search-server 4002 sync-search-indices",
|
||||
|
||||
@@ -68,6 +68,9 @@
|
||||
.z-2 {
|
||||
z-index: 2;
|
||||
}
|
||||
.z-3 {
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
/* Blue primary button
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
@@ -7,7 +7,7 @@ describe('header', () => {
|
||||
|
||||
test('includes localized meta tags', async () => {
|
||||
const $ = await getDOM('/en')
|
||||
expect($('meta[name="next-head-count"]').length).toBe(1)
|
||||
expect($('link[rel="alternate"]').length).toBeGreaterThan(2)
|
||||
})
|
||||
|
||||
test("includes a link to the homepage (in the current page's language)", async () => {
|
||||
@@ -26,26 +26,30 @@ describe('header', () => {
|
||||
)
|
||||
expect(
|
||||
$(
|
||||
'[data-testid=language-picker] a[href="/ja/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/managing-a-branch-protection-rule"]'
|
||||
'[data-testid=desktop-header] [data-testid=language-picker] a[href="/ja/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/managing-a-branch-protection-rule"]'
|
||||
).length
|
||||
).toBe(1)
|
||||
})
|
||||
|
||||
test('display the native name and the English name for each translated language', async () => {
|
||||
const $ = await getDOM('/en')
|
||||
expect($('[data-testid=language-picker] a[href="/en/"]').text().trim()).toBe('English')
|
||||
expect($('[data-testid=language-picker] a[href="/cn/"]').text().trim()).toBe(
|
||||
'简体中文 (Simplified Chinese)'
|
||||
)
|
||||
expect($('[data-testid=language-picker] a[href="/ja/"]').text().trim()).toBe(
|
||||
'日本語 (Japanese)'
|
||||
)
|
||||
|
||||
expect(
|
||||
$('[data-testid=desktop-header] [data-testid=language-picker] a[href="/en"]').text().trim()
|
||||
).toBe('English')
|
||||
expect(
|
||||
$('[data-testid=desktop-header] [data-testid=language-picker] a[href="/cn"]').text().trim()
|
||||
).toBe('简体中文 (Simplified Chinese)')
|
||||
expect(
|
||||
$('[data-testid=desktop-header] [data-testid=language-picker] a[href="/ja"]').text().trim()
|
||||
).toBe('日本語 (Japanese)')
|
||||
})
|
||||
|
||||
test('emphasize the current language', async () => {
|
||||
const $ = await getDOM('/en')
|
||||
expect($('[data-testid=language-picker] a[href="/en/"]').length).toBe(1)
|
||||
expect($('[data-testid=language-picker] a[href="/ja/"]').length).toBe(1)
|
||||
expect($('[data-testid=desktop-header] [data-testid=language-picker] summary').text()).toBe(
|
||||
'English'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -136,15 +140,15 @@ describe('header', () => {
|
||||
const $ = await getDOM(
|
||||
'/en/github/importing-your-projects-to-github/importing-source-code-to-github/about-github-importer'
|
||||
)
|
||||
const github = $('#homepages a.active[href="/en/github"]')
|
||||
const github = $('[data-testid=current-product][data-current-product-path="/github"]')
|
||||
expect(github.length).toBe(1)
|
||||
expect(github.text().trim()).toBe('GitHub')
|
||||
expect(github.attr('class').includes('active')).toBe(true)
|
||||
|
||||
const ghe = $(`#homepages a[href="/en/enterprise-server@${latest}/admin"]`)
|
||||
const ghe = $(
|
||||
`[data-testid=product-picker-list] a[href="/en/enterprise-server@${latest}/admin"]`
|
||||
)
|
||||
expect(ghe.length).toBe(1)
|
||||
expect(ghe.text().trim()).toBe('Enterprise administrators')
|
||||
expect(ghe.attr('class').includes('active')).toBe(false)
|
||||
})
|
||||
|
||||
// Skipped. See issues/923
|
||||
@@ -152,17 +156,21 @@ describe('header', () => {
|
||||
const $ = await getDOM(
|
||||
'/ja/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests'
|
||||
)
|
||||
expect($('#homepages a.active[href="/ja/repositories"]').length).toBe(1)
|
||||
expect($(`#homepages a[href="/ja/enterprise-server@${latest}/admin"]`).length).toBe(1)
|
||||
expect(
|
||||
$('[data-testid=current-product][data-current-product-path="/repositories"]').length
|
||||
).toBe(1)
|
||||
expect(
|
||||
$(`[data-testid=product-picker-list] a[href="/ja/enterprise-server@${latest}/admin"]`)
|
||||
.length
|
||||
).toBe(1)
|
||||
})
|
||||
|
||||
test('emphasizes the product that corresponds to the current page', async () => {
|
||||
const $ = await getDOM(
|
||||
`/en/enterprise/${oldestSupported}/user/github/importing-your-projects-to-github/importing-source-code-to-github/importing-a-git-repository-using-the-command-line`
|
||||
`/en/enterprise-server@${oldestSupported}/github/importing-your-projects-to-github/importing-source-code-to-github/importing-a-git-repository-using-the-command-line`
|
||||
)
|
||||
expect($(`#homepages a.active[href="/en/enterprise-server@${latest}/admin"]`).length).toBe(0)
|
||||
expect($('#homepages a[href="/en/github"]').length).toBe(1)
|
||||
expect($('#homepages a.active[href="/en/github"]').length).toBe(1)
|
||||
|
||||
expect($('[data-testid=current-product]').text()).toBe('GitHub')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3,9 +3,9 @@ import { jest } from '@jest/globals'
|
||||
|
||||
jest.setTimeout(3 * 60 * 1000)
|
||||
|
||||
describe.skip('learning tracks', () => {
|
||||
describe('learning tracks', () => {
|
||||
test('render first track as feature track', async () => {
|
||||
const $ = await getDOM('/en/actions/guides')
|
||||
const $ = await getDOM('/en/code-security/guides')
|
||||
expect($('[data-testid=feature-track]')).toHaveLength(1)
|
||||
const href = $('[data-testid=feature-track] li a').first().attr('href')
|
||||
const found = href.match(/.*\?learn=(.*)/i)
|
||||
@@ -19,7 +19,7 @@ describe.skip('learning tracks', () => {
|
||||
})
|
||||
|
||||
test('render other tracks', async () => {
|
||||
const $ = await getDOM('/en/actions/guides')
|
||||
const $ = await getDOM('/en/code-security/guides')
|
||||
expect($('[data-testid=learning-track]').length).toBeGreaterThanOrEqual(4)
|
||||
$('[data-testid=learning-track]').each((i, trackElem) => {
|
||||
const href = $(trackElem).find('.Box-header a').first().attr('href')
|
||||
@@ -37,16 +37,16 @@ describe.skip('learning tracks', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe.skip('navigation banner', () => {
|
||||
describe('navigation banner', () => {
|
||||
test('render navigation banner when url includes correct learning track name', async () => {
|
||||
const $ = await getDOM(
|
||||
'/en/actions/guides/setting-up-continuous-integration-using-workflow-templates?learn=continuous_integration'
|
||||
'/en/code-security/security-advisories/creating-a-security-advisory?learn=security_advisories'
|
||||
)
|
||||
expect($('[data-testid=learning-track-nav]')).toHaveLength(1)
|
||||
const $navLinks = $('[data-testid=learning-track-nav] a')
|
||||
expect($navLinks).toHaveLength(2)
|
||||
$navLinks.each((i, elem) => {
|
||||
expect($(elem).attr('href')).toEqual(expect.stringContaining('?learn=continuous_integration'))
|
||||
expect($(elem).attr('href')).toEqual(expect.stringContaining('?learn=security_advisories'))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -62,6 +62,47 @@ describe.skip('navigation banner', () => {
|
||||
})
|
||||
})
|
||||
|
||||
test('render navigation banner when url belongs to a multi-product learning track', async () => {
|
||||
// This is a `code-security` product learning track and it includes a guide
|
||||
// path that belongs to the `repositories` product.
|
||||
const $ = await getDOM(
|
||||
'/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-security-and-analysis-settings-for-your-repository?learn=dependabot_alerts&learnProduct=code-security'
|
||||
)
|
||||
expect($('[data-testid=learning-track-nav]')).toHaveLength(1)
|
||||
const $navLinks = $('[data-testid=learning-track-nav] a')
|
||||
expect($navLinks).toHaveLength(2)
|
||||
$navLinks.each((i, elem) => {
|
||||
expect($(elem).attr('href')).toEqual(
|
||||
expect.stringContaining('?learn=dependabot_alerts&learnProduct=code-security')
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
test('render navigation banner when url belongs to a learning track and has an incorrect `learnProduct` param', async () => {
|
||||
// This is a `code-security` product learning track so the path should
|
||||
// work as-is and we won't check `learnProduct`.
|
||||
const $ = await getDOM(
|
||||
'/en/code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/viewing-and-updating-vulnerable-dependencies-in-your-repository?learn=dependabot_alerts&learnProduct=not_real'
|
||||
)
|
||||
expect($('[data-testid=learning-track-nav]')).toHaveLength(1)
|
||||
const $navLinks = $('[data-testid=learning-track-nav] a')
|
||||
expect($navLinks).toHaveLength(2)
|
||||
$navLinks.each((i, elem) => {
|
||||
expect($(elem).attr('href')).toEqual(
|
||||
expect.stringContaining('?learn=dependabot_alerts&learnProduct=code-security')
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
test('does not include banner with multi-product learning track and when url has incorrect `learnProduct` param', async () => {
|
||||
// This is a `code-security` product learning track and it includes a guide
|
||||
// path that belongs to the `repositories` product.
|
||||
const $ = await getDOM(
|
||||
'/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-security-and-analysis-settings-for-your-repository?learn=dependabot_alerts&learnProduct=not_real'
|
||||
)
|
||||
expect($('[data-testid=learning-track-nav]')).toHaveLength(0)
|
||||
})
|
||||
|
||||
test('does not include banner when url does not include `learn` param', async () => {
|
||||
const $ = await getDOM(
|
||||
'/en/actions/guides/setting-up-continuous-integration-using-workflow-templates'
|
||||
|
||||
@@ -545,7 +545,7 @@ describe('server', () => {
|
||||
$(
|
||||
`[data-testid=article-version-picker] a[href="/en/enterprise-server@${enterpriseServerReleases.latest}/${articlePath}"]`
|
||||
).length
|
||||
).toBe(2)
|
||||
).toBe(1)
|
||||
// 2.13 predates this feature, so it should be excluded:
|
||||
expect(
|
||||
$(`[data-testid=article-version-picker] a[href="/en/enterprise/2.13/user/${articlePath}"]`)
|
||||
|
||||
@@ -25,28 +25,34 @@ describe('products module', () => {
|
||||
describe('mobile-only products nav', () => {
|
||||
test('renders current product on various product pages for each product', async () => {
|
||||
// Note the unversioned homepage at `/` does not have a product selected in the mobile dropdown
|
||||
expect((await getDOM('/github'))('#current-product').text().trim()).toBe('GitHub')
|
||||
expect((await getDOM('/github'))('[data-testid=current-product]').text().trim()).toBe('GitHub')
|
||||
|
||||
// Enterprise server
|
||||
expect((await getDOM('/en/enterprise/admin'))('#current-product').text().trim()).toBe(
|
||||
'Enterprise administrators'
|
||||
)
|
||||
expect(
|
||||
(await getDOM('/en/enterprise/admin'))('[data-testid=current-product]').text().trim()
|
||||
).toBe('Enterprise administrators')
|
||||
expect(
|
||||
(
|
||||
await getDOM(
|
||||
'/en/enterprise/user/github/importing-your-projects-to-github/importing-source-code-to-github/importing-a-git-repository-using-the-command-line'
|
||||
)
|
||||
)('#current-product')
|
||||
)('[data-testid=current-product]')
|
||||
.text()
|
||||
.trim()
|
||||
).toBe('GitHub')
|
||||
|
||||
expect((await getDOM('/desktop'))('#current-product').text().trim()).toBe('GitHub Desktop')
|
||||
expect((await getDOM('/desktop'))('[data-testid=current-product]').text().trim()).toBe(
|
||||
'GitHub Desktop'
|
||||
)
|
||||
|
||||
expect((await getDOM('/actions'))('#current-product').text().trim()).toBe('GitHub Actions')
|
||||
expect((await getDOM('/actions'))('[data-testid=current-product]').text().trim()).toBe(
|
||||
'GitHub Actions'
|
||||
)
|
||||
|
||||
// localized
|
||||
expect((await getDOM('/ja/desktop'))('#current-product').text().trim()).toBe('GitHub Desktop')
|
||||
expect((await getDOM('/ja/desktop'))('[data-testid=current-product]').text().trim()).toBe(
|
||||
'GitHub Desktop'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -24,9 +24,6 @@ featuredLinks:
|
||||
- /codespaces/setting-up-your-codespace/personalizing-codespaces-for-your-account
|
||||
popularHeading: Set up your project
|
||||
product_video: 'https://www.youtube-nocookie.com/embed/_W9B7qc9lVc'
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/codespaces-feedback'
|
||||
redirect_from:
|
||||
- /github/developing-online-with-github-codespaces
|
||||
- /github/developing-online-with-codespaces
|
||||
|
||||
@@ -26,9 +26,6 @@ changelog:
|
||||
examples_source: data/product-examples/discussions/community-examples.yml
|
||||
product_video: 'https://www.youtube-nocookie.com/embed/IpBw2SJkFyk'
|
||||
layout: product-landing
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/discussions-feedback'
|
||||
versions:
|
||||
fpt: '*'
|
||||
children:
|
||||
|
||||
@@ -34,9 +34,6 @@ children:
|
||||
- /receiving-sponsorships-through-github-sponsors
|
||||
- /integrating-with-github-sponsors
|
||||
- /guides
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/sponsors-feedback'
|
||||
---
|
||||
|
||||
<!---->
|
||||
|
||||
@@ -24,9 +24,6 @@ featuredLinks:
|
||||
- /codespaces/setting-up-your-codespace/personalizing-codespaces-for-your-account
|
||||
popularHeading: Set up your project
|
||||
product_video: 'https://www.youtube-nocookie.com/embed/_W9B7qc9lVc'
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/codespaces-feedback'
|
||||
redirect_from:
|
||||
- /github/developing-online-with-github-codespaces
|
||||
- /github/developing-online-with-codespaces
|
||||
|
||||
@@ -34,9 +34,6 @@ children:
|
||||
- /receiving-sponsorships-through-github-sponsors
|
||||
- /integrating-with-github-sponsors
|
||||
- /guides
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/sponsors-feedback'
|
||||
---
|
||||
|
||||
<!---->
|
||||
|
||||
@@ -24,9 +24,6 @@ featuredLinks:
|
||||
- /codespaces/setting-up-your-codespace/personalizing-codespaces-for-your-account
|
||||
popularHeading: Set up your project
|
||||
product_video: 'https://www.youtube-nocookie.com/embed/_W9B7qc9lVc'
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/codespaces-feedback'
|
||||
redirect_from:
|
||||
- /github/developing-online-with-github-codespaces
|
||||
- /github/developing-online-with-codespaces
|
||||
|
||||
@@ -26,9 +26,6 @@ changelog:
|
||||
examples_source: data/product-examples/discussions/community-examples.yml
|
||||
product_video: 'https://www.youtube-nocookie.com/embed/IpBw2SJkFyk'
|
||||
layout: product-landing
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/discussions-feedback'
|
||||
versions:
|
||||
fpt: '*'
|
||||
children:
|
||||
|
||||
@@ -34,9 +34,6 @@ children:
|
||||
- /receiving-sponsorships-through-github-sponsors
|
||||
- /integrating-with-github-sponsors
|
||||
- /guides
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/sponsors-feedback'
|
||||
---
|
||||
|
||||
<!---->
|
||||
|
||||
@@ -24,9 +24,6 @@ featuredLinks:
|
||||
- /codespaces/setting-up-your-codespace/personalizing-codespaces-for-your-account
|
||||
popularHeading: Set up your project
|
||||
product_video: 'https://www.youtube-nocookie.com/embed/_W9B7qc9lVc'
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/codespaces-feedback'
|
||||
redirect_from:
|
||||
- /github/developing-online-with-github-codespaces
|
||||
- /github/developing-online-with-codespaces
|
||||
|
||||
@@ -26,9 +26,6 @@ changelog:
|
||||
examples_source: data/product-examples/discussions/community-examples.yml
|
||||
product_video: 'https://www.youtube-nocookie.com/embed/IpBw2SJkFyk'
|
||||
layout: product-landing
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/discussions-feedback'
|
||||
versions:
|
||||
fpt: '*'
|
||||
children:
|
||||
|
||||
@@ -34,9 +34,6 @@ children:
|
||||
- /receiving-sponsorships-through-github-sponsors
|
||||
- /integrating-with-github-sponsors
|
||||
- /guides
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/sponsors-feedback'
|
||||
---
|
||||
|
||||
<!---->
|
||||
|
||||
@@ -24,9 +24,6 @@ featuredLinks:
|
||||
- /codespaces/setting-up-your-codespace/personalizing-codespaces-for-your-account
|
||||
popularHeading: Set up your project
|
||||
product_video: 'https://www.youtube-nocookie.com/embed/_W9B7qc9lVc'
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/codespaces-feedback'
|
||||
redirect_from:
|
||||
- /github/developing-online-with-github-codespaces
|
||||
- /github/developing-online-with-codespaces
|
||||
|
||||
@@ -26,9 +26,6 @@ changelog:
|
||||
examples_source: data/product-examples/discussions/community-examples.yml
|
||||
product_video: 'https://www.youtube-nocookie.com/embed/IpBw2SJkFyk'
|
||||
layout: product-landing
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/discussions-feedback'
|
||||
versions:
|
||||
fpt: '*'
|
||||
children:
|
||||
|
||||
@@ -34,9 +34,6 @@ children:
|
||||
- /receiving-sponsorships-through-github-sponsors
|
||||
- /integrating-with-github-sponsors
|
||||
- /guides
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/sponsors-feedback'
|
||||
---
|
||||
|
||||
<!---->
|
||||
|
||||
@@ -24,9 +24,6 @@ featuredLinks:
|
||||
- /codespaces/setting-up-your-codespace/personalizing-codespaces-for-your-account
|
||||
popularHeading: Set up your project
|
||||
product_video: 'https://www.youtube-nocookie.com/embed/_W9B7qc9lVc'
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/codespaces-feedback'
|
||||
redirect_from:
|
||||
- /github/developing-online-with-github-codespaces
|
||||
- /github/developing-online-with-codespaces
|
||||
|
||||
@@ -26,9 +26,6 @@ changelog:
|
||||
examples_source: data/product-examples/discussions/community-examples.yml
|
||||
product_video: 'https://www.youtube-nocookie.com/embed/IpBw2SJkFyk'
|
||||
layout: product-landing
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/discussions-feedback'
|
||||
versions:
|
||||
fpt: '*'
|
||||
children:
|
||||
|
||||
@@ -34,9 +34,6 @@ children:
|
||||
- /receiving-sponsorships-through-github-sponsors
|
||||
- /integrating-with-github-sponsors
|
||||
- /guides
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/sponsors-feedback'
|
||||
---
|
||||
|
||||
<!---->
|
||||
|
||||
@@ -24,9 +24,6 @@ featuredLinks:
|
||||
- /codespaces/setting-up-your-codespace/personalizing-codespaces-for-your-account
|
||||
popularHeading: Set up your project
|
||||
product_video: 'https://www.youtube-nocookie.com/embed/_W9B7qc9lVc'
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/codespaces-feedback'
|
||||
redirect_from:
|
||||
- /github/developing-online-with-github-codespaces
|
||||
- /github/developing-online-with-codespaces
|
||||
|
||||
@@ -26,9 +26,6 @@ changelog:
|
||||
examples_source: data/product-examples/discussions/community-examples.yml
|
||||
product_video: 'https://www.youtube-nocookie.com/embed/IpBw2SJkFyk'
|
||||
layout: product-landing
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/discussions-feedback'
|
||||
versions:
|
||||
fpt: '*'
|
||||
children:
|
||||
|
||||
@@ -34,9 +34,6 @@ children:
|
||||
- /receiving-sponsorships-through-github-sponsors
|
||||
- /integrating-with-github-sponsors
|
||||
- /guides
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/sponsors-feedback'
|
||||
---
|
||||
|
||||
<!---->
|
||||
|
||||
Reference in New Issue
Block a user