Merge branch 'main' into codewithdev-docs
This commit is contained in:
@@ -17,11 +17,11 @@ jobs:
|
|||||||
const repo = context.payload.repository.name
|
const repo = context.payload.repository.name
|
||||||
|
|
||||||
const allStatusLabels = [
|
const allStatusLabels = [
|
||||||
'Status: GREEN',
|
'green',
|
||||||
'Status: GREY',
|
'grey',
|
||||||
'Status: YELLOW',
|
'yellow',
|
||||||
'Status: BLACK',
|
'black',
|
||||||
'Status: RED'
|
'red'
|
||||||
];
|
];
|
||||||
|
|
||||||
const currentLabels = await github.issues.listLabelsOnIssue({
|
const currentLabels = await github.issues.listLabelsOnIssue({
|
||||||
@@ -33,7 +33,7 @@ jobs:
|
|||||||
const newLabels = currentLabels.data.filter( label => allStatusLabels.includes(label.name) === false)
|
const newLabels = currentLabels.data.filter( label => allStatusLabels.includes(label.name) === false)
|
||||||
|
|
||||||
allStatusLabels.forEach( label => {
|
allStatusLabels.forEach( label => {
|
||||||
if(context.payload.comment.body.includes(label)) {
|
if(context.payload.comment.body.toLowerCase().includes(`status: ${label}`)) {
|
||||||
newLabels.push(label)
|
newLabels.push(label)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 74 KiB |
@@ -1,7 +1,7 @@
|
|||||||
import cx from 'classnames'
|
import cx from 'classnames'
|
||||||
import Link from 'next/link'
|
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useMainContext } from './context/MainContext'
|
import { useMainContext } from './context/MainContext'
|
||||||
|
import { Link } from 'components/Link'
|
||||||
|
|
||||||
export type BreadcrumbT = {
|
export type BreadcrumbT = {
|
||||||
title: string
|
title: string
|
||||||
@@ -12,7 +12,7 @@ export type BreadcrumbT = {
|
|||||||
type Props = {}
|
type Props = {}
|
||||||
export const Breadcrumbs = (props: Props) => {
|
export const Breadcrumbs = (props: Props) => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const pathWithLocale = `/${router.locale}${router.asPath}`
|
const pathWithLocale = `/${router.locale}${router.asPath.split('?')[0]}` // remove query string
|
||||||
const { breadcrumbs } = useMainContext()
|
const { breadcrumbs } = useMainContext()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -28,16 +28,16 @@ export const Breadcrumbs = (props: Props) => {
|
|||||||
{breadcrumb.title}
|
{breadcrumb.title}
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<Link key={title} href={breadcrumb.href}>
|
<Link
|
||||||
<a
|
key={title}
|
||||||
title={title}
|
href={breadcrumb.href}
|
||||||
className={cx(
|
title={title}
|
||||||
'd-inline-block',
|
className={cx(
|
||||||
pathWithLocale === breadcrumb.href && 'color-text-tertiary'
|
'd-inline-block',
|
||||||
)}
|
pathWithLocale === breadcrumb.href && 'color-text-tertiary'
|
||||||
>
|
)}
|
||||||
{breadcrumb.title}
|
>
|
||||||
</a>
|
{breadcrumb.title}
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ export const DefaultLayout = (props: Props) => {
|
|||||||
<title>{page.fullTitle}</title>
|
<title>{page.fullTitle}</title>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<link rel="stylesheet" href={builtAssets.main.css} />
|
|
||||||
<script id="expose" type="application/json" dangerouslySetInnerHTML={{ __html: expose }} />
|
<script id="expose" type="application/json" dangerouslySetInnerHTML={{ __html: expose }} />
|
||||||
<script src={builtAssets.main.js} />
|
<script src={builtAssets.main.js} />
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import Link from 'next/link'
|
|
||||||
import cx from 'classnames'
|
import cx from 'classnames'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { ChevronDownIcon, MarkGithubIcon, ThreeBarsIcon, XIcon } from '@primer/octicons-react'
|
import { ChevronDownIcon, MarkGithubIcon, ThreeBarsIcon, XIcon } from '@primer/octicons-react'
|
||||||
import { ButtonOutline } from '@primer/components'
|
import { ButtonOutline } from '@primer/components'
|
||||||
|
|
||||||
|
import { Link } from 'components/Link'
|
||||||
import { useMainContext } from './context/MainContext'
|
import { useMainContext } from './context/MainContext'
|
||||||
import { LanguagePicker } from './LanguagePicker'
|
import { LanguagePicker } from './LanguagePicker'
|
||||||
import { HeaderNotifications } from 'components/HeaderNotifications'
|
import { HeaderNotifications } from 'components/HeaderNotifications'
|
||||||
@@ -34,16 +34,15 @@ export const Header = () => {
|
|||||||
id="github-logo-mobile"
|
id="github-logo-mobile"
|
||||||
role="banner"
|
role="banner"
|
||||||
>
|
>
|
||||||
<Link href={`/${router.locale}`}>
|
<Link aria-hidden="true" tabIndex={-1} href={`/${router.locale}`}>
|
||||||
<a aria-hidden="true" tabIndex={-1}>
|
<MarkGithubIcon size={32} className="color-icon-primary" />
|
||||||
<MarkGithubIcon size={32} className="color-icon-primary" />
|
|
||||||
</a>
|
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<Link href={`/${router.locale}`}>
|
<Link
|
||||||
<a className="h4-mktg color-text-primary no-underline no-wrap pl-2">
|
href={`/${router.locale}`}
|
||||||
{t('github_docs')}
|
className="h4-mktg color-text-primary no-underline no-wrap pl-2"
|
||||||
</a>
|
>
|
||||||
|
{t('github_docs')}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export const HeaderNotifications = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{allNotifications.map(({ type, content }, i) => {
|
{allNotifications.map(({ type, content }, i) => {
|
||||||
const isLast = i !== allNotifications.length - 1
|
const isLast = i === allNotifications.length - 1
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cx(
|
className={cx(
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import Link from 'next/link'
|
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { Dropdown } from '@primer/components'
|
import { Dropdown } from '@primer/components'
|
||||||
|
|
||||||
|
import { Link } from 'components/Link'
|
||||||
import { useMainContext } from './context/MainContext'
|
import { useMainContext } from './context/MainContext'
|
||||||
|
|
||||||
export const LanguagePicker = () => {
|
export const LanguagePicker = () => {
|
||||||
@@ -12,7 +13,13 @@ export const LanguagePicker = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="ml-4 d-flex flex-justify-center flex-items-center">
|
<div className="ml-4 d-flex flex-justify-center flex-items-center">
|
||||||
<Dropdown css>
|
<Dropdown
|
||||||
|
css={`
|
||||||
|
ul {
|
||||||
|
width: unset;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
<summary>
|
<summary>
|
||||||
{selectedLang.nativeName || selectedLang.name}
|
{selectedLang.nativeName || selectedLang.name}
|
||||||
<Dropdown.Caret />
|
<Dropdown.Caret />
|
||||||
@@ -22,15 +29,13 @@ export const LanguagePicker = () => {
|
|||||||
return (
|
return (
|
||||||
<Dropdown.Item key={lang.code}>
|
<Dropdown.Item key={lang.code}>
|
||||||
<Link href={router.asPath} locale={lang.hreflang}>
|
<Link href={router.asPath} locale={lang.hreflang}>
|
||||||
<a>
|
{lang.nativeName ? (
|
||||||
{lang.nativeName ? (
|
<>
|
||||||
<>
|
{lang.nativeName} ({lang.name})
|
||||||
{lang.nativeName} ({lang.name})
|
</>
|
||||||
</>
|
) : (
|
||||||
) : (
|
lang.name
|
||||||
lang.name
|
)}
|
||||||
)}
|
|
||||||
</a>
|
|
||||||
</Link>
|
</Link>
|
||||||
</Dropdown.Item>
|
</Dropdown.Item>
|
||||||
)
|
)
|
||||||
|
|||||||
25
components/Link.tsx
Normal file
25
components/Link.tsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import NextLink from 'next/link'
|
||||||
|
import { ComponentProps } from 'react'
|
||||||
|
|
||||||
|
const { NODE_ENV } = process.env
|
||||||
|
|
||||||
|
const enableNextLinks = false
|
||||||
|
|
||||||
|
type Props = { locale?: string } & ComponentProps<'a'>
|
||||||
|
export function Link(props: Props) {
|
||||||
|
const { href, locale, ...restProps } = props
|
||||||
|
|
||||||
|
if (!href && NODE_ENV !== 'production') {
|
||||||
|
console.warn('Missing href on Link')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enableNextLinks) {
|
||||||
|
return (
|
||||||
|
<NextLink href={href || ''} locale={locale}>
|
||||||
|
<a {...restProps} />
|
||||||
|
</NextLink>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return <a href={locale ? `/${locale}${href}` : href} {...restProps} />
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import Link from 'next/link'
|
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { LinkExternalIcon } from '@primer/octicons-react'
|
import { LinkExternalIcon } from '@primer/octicons-react'
|
||||||
import cx from 'classnames'
|
import cx from 'classnames'
|
||||||
|
|
||||||
|
import { Link } from 'components/Link'
|
||||||
import { useMainContext } from 'components/context/MainContext'
|
import { useMainContext } from 'components/context/MainContext'
|
||||||
|
|
||||||
export const MobileProductDropdown = () => {
|
export const MobileProductDropdown = () => {
|
||||||
@@ -20,22 +20,19 @@ export const MobileProductDropdown = () => {
|
|||||||
<Link
|
<Link
|
||||||
key={product.id}
|
key={product.id}
|
||||||
href={`${product.external ? '' : `/${router.locale}`}${product.href}`}
|
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'
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<a
|
{product.name}
|
||||||
className={cx(
|
{product.external && (
|
||||||
'd-block py-2',
|
<span className="ml-1">
|
||||||
product.id === currentProduct.id
|
<LinkExternalIcon size="small" />
|
||||||
? 'color-text-link text-underline active'
|
</span>
|
||||||
: 'Link--primary no-underline'
|
)}
|
||||||
)}
|
|
||||||
>
|
|
||||||
{product.name}
|
|
||||||
{product.external && (
|
|
||||||
<span className="ml-1">
|
|
||||||
<LinkExternalIcon size="small" />
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</a>
|
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -45,17 +45,6 @@ export const ScrollButton = () => {
|
|||||||
>
|
>
|
||||||
<ChevronUpIcon />
|
<ChevronUpIcon />
|
||||||
</button>
|
</button>
|
||||||
<style jsx>{`
|
|
||||||
.opacity-0 {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
.opacity-100 {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
.transition-200 {
|
|
||||||
transition: 200ms;
|
|
||||||
}
|
|
||||||
`}</style>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import Link from 'next/link'
|
|
||||||
import { LinkExternalIcon, MarkGithubIcon } from '@primer/octicons-react'
|
import { LinkExternalIcon, MarkGithubIcon } from '@primer/octicons-react'
|
||||||
|
|
||||||
|
import { Link } from 'components/Link'
|
||||||
import { useTranslation } from './hooks/useTranslation'
|
import { useTranslation } from './hooks/useTranslation'
|
||||||
import { useMainContext } from './context/MainContext'
|
import { useMainContext } from './context/MainContext'
|
||||||
import { SidebarProduct } from './product/SidebarProduct'
|
import { SidebarProduct } from './product/SidebarProduct'
|
||||||
@@ -22,15 +23,19 @@ export const SidebarNav = (props: Props) => {
|
|||||||
id="github-logo"
|
id="github-logo"
|
||||||
role="banner"
|
role="banner"
|
||||||
>
|
>
|
||||||
<Link href={`/${router.locale}`}>
|
<Link
|
||||||
<a className="color-text-primary" aria-hidden="true" tabIndex={-1}>
|
href={`/${router.locale}`}
|
||||||
<MarkGithubIcon size={32} />
|
className="color-text-primary"
|
||||||
</a>
|
aria-hidden="true"
|
||||||
|
tabIndex={-1}
|
||||||
|
>
|
||||||
|
<MarkGithubIcon size={32} />
|
||||||
</Link>
|
</Link>
|
||||||
<Link href={`/${router.locale}`}>
|
<Link
|
||||||
<a className="h4-mktg color-text-primary no-underline no-wrap pl-2 flex-auto">
|
href={`/${router.locale}`}
|
||||||
{t('github_docs')}
|
className="h4-mktg color-text-primary no-underline no-wrap pl-2 flex-auto"
|
||||||
</a>
|
>
|
||||||
|
{t('github_docs')}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<nav>
|
<nav>
|
||||||
|
|||||||
@@ -8,14 +8,15 @@ type Props = {
|
|||||||
className?: string
|
className?: string
|
||||||
}
|
}
|
||||||
export const TruncateLines = (props: Props) => {
|
export const TruncateLines = (props: Props) => {
|
||||||
const Component = props.as || 'div'
|
const { as, maxLines, className, children } = props
|
||||||
|
const Component = as || 'div'
|
||||||
return (
|
return (
|
||||||
<Component className={cx('root', props.className)}>
|
<Component className={cx('root', className)}>
|
||||||
{props.children}
|
{children}
|
||||||
<style jsx>{`
|
<style jsx>{`
|
||||||
.root {
|
.root {
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
-webkit-line-clamp: ${props.maxLines};
|
-webkit-line-clamp: ${maxLines};
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
import Link from 'next/link'
|
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
import { Dropdown } from '@primer/components'
|
|
||||||
import { useMainContext } from './context/MainContext'
|
|
||||||
import { useVersion } from './hooks/useVersion'
|
|
||||||
|
|
||||||
export const VersionPicker = () => {
|
|
||||||
const router = useRouter()
|
|
||||||
const { currentVersion } = useVersion()
|
|
||||||
const { allVersions } = useMainContext()
|
|
||||||
|
|
||||||
const versions = Object.values(allVersions)
|
|
||||||
const activeVersion = allVersions[currentVersion]
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="ml-4 d-flex flex-justify-center flex-items-center">
|
|
||||||
<Dropdown css>
|
|
||||||
<summary>
|
|
||||||
{activeVersion.versionTitle}
|
|
||||||
<Dropdown.Caret />
|
|
||||||
</summary>
|
|
||||||
<Dropdown.Menu direction="sw">
|
|
||||||
{versions.map((version) => {
|
|
||||||
return (
|
|
||||||
<Dropdown.Item key={version.version}>
|
|
||||||
<Link
|
|
||||||
href={{
|
|
||||||
pathname: router.pathname,
|
|
||||||
query: {
|
|
||||||
...router.query,
|
|
||||||
versionId: version.version,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<a>{version.versionTitle}</a>
|
|
||||||
</Link>
|
|
||||||
</Dropdown.Item>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</Dropdown.Menu>
|
|
||||||
</Dropdown>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
31
components/article/ArticleTitle.tsx
Normal file
31
components/article/ArticleTitle.tsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { Tooltip, Link } from '@primer/components'
|
||||||
|
import { PrinterIcon } from './PrinterIcon'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
children: React.ReactNode
|
||||||
|
}
|
||||||
|
export const ArticleTitle = ({ children }: Props) => {
|
||||||
|
return (
|
||||||
|
<div className="d-flex flex-items-baseline flex-justify-between">
|
||||||
|
<h1 className="my-4">{children}</h1>
|
||||||
|
<div className="d-none d-lg-block ml-2">
|
||||||
|
<Tooltip aria-label="Print this article" noDelay direction="n">
|
||||||
|
<Link
|
||||||
|
as="button"
|
||||||
|
underline={false}
|
||||||
|
muted
|
||||||
|
onClick={() => {
|
||||||
|
try {
|
||||||
|
document.execCommand('print', false)
|
||||||
|
} catch (e) {
|
||||||
|
window.print()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PrinterIcon />
|
||||||
|
</Link>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import Link from 'next/link'
|
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { Dropdown } from '@primer/components'
|
import { Dropdown } from '@primer/components'
|
||||||
|
|
||||||
|
import { Link } from 'components/Link'
|
||||||
import { useMainContext } from 'components/context/MainContext'
|
import { useMainContext } from 'components/context/MainContext'
|
||||||
import { useVersion } from 'components/hooks/useVersion'
|
import { useVersion } from 'components/hooks/useVersion'
|
||||||
import { useTranslation } from 'components/hooks/useTranslation'
|
import { useTranslation } from 'components/hooks/useTranslation'
|
||||||
@@ -17,42 +17,39 @@ export const ArticleVersionPicker = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="d-none d-lg-flex flex-justify-end">
|
<Dropdown
|
||||||
<Dropdown
|
css={`
|
||||||
css={`
|
ul {
|
||||||
ul {
|
width: unset;
|
||||||
width: unset;
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<summary className="f4 h5-mktg btn-outline-mktg btn-mktg p-2">
|
||||||
|
<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) => {
|
||||||
|
if (permalink.pageVersion === 'homepage') {
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
`}
|
|
||||||
>
|
|
||||||
<summary className="f4 h5-mktg btn-outline-mktg btn-mktg p-2">
|
|
||||||
<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) => {
|
|
||||||
if (permalink.pageVersion === 'homepage') {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown.Item key={permalink.href}>
|
<Dropdown.Item key={permalink.href}>
|
||||||
<Link href={permalink.href}>
|
<Link href={permalink.href}>{permalink.pageVersionTitle}</Link>
|
||||||
<a>{permalink.pageVersionTitle}</a>
|
</Dropdown.Item>
|
||||||
</Link>
|
)
|
||||||
</Dropdown.Item>
|
})}
|
||||||
)
|
<div className="pb-1">
|
||||||
})}
|
<Link
|
||||||
<div className="pb-1">
|
href={`/${router.locale}/${enterpriseServerVersions[0]}/admin/all-releases`}
|
||||||
<Link href={`/${router.locale}/${enterpriseServerVersions[0]}/admin/all-releases`}>
|
className="f6 no-underline color-text-tertiary pl-3 pr-2 no-wrap"
|
||||||
<a className="f6 no-underline color-text-tertiary pl-3 pr-2 no-wrap">
|
>
|
||||||
See all Enterprise releases
|
See all Enterprise releases
|
||||||
</a>
|
</Link>
|
||||||
</Link>
|
</div>
|
||||||
</div>
|
</Dropdown.Menu>
|
||||||
</Dropdown.Menu>
|
</Dropdown>
|
||||||
</Dropdown>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
20
components/article/PrinterIcon.tsx
Normal file
20
components/article/PrinterIcon.tsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// From https://heroicons.com
|
||||||
|
export const PrinterIcon = () => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
height={18}
|
||||||
|
width={18}
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M17 17h2a2 2 0 002-2v-4a2 2 0 00-2-2H5a2 2 0 00-2 2v4a2 2 0 002 2h2m2 4h6a2 2 0 002-2v-4a2 2 0 00-2-2H9a2 2 0 00-2 2v4a2 2 0 002 2zm8-12V5a2 2 0 00-2-2H9a2 2 0 00-2 2v4h10z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -67,7 +67,7 @@ export type MainContextT = {
|
|||||||
maptopic?: BreadcrumbT
|
maptopic?: BreadcrumbT
|
||||||
article?: BreadcrumbT
|
article?: BreadcrumbT
|
||||||
}
|
}
|
||||||
builtAssets: { main: { css: string; js: string } }
|
builtAssets: { main: { js: string } }
|
||||||
expose: string
|
expose: string
|
||||||
activeProducts: Array<ProductT>
|
activeProducts: Array<ProductT>
|
||||||
currentProduct: ProductT
|
currentProduct: ProductT
|
||||||
@@ -84,6 +84,7 @@ export type MainContextT = {
|
|||||||
currentProductTree?: CurrentProductTree
|
currentProductTree?: CurrentProductTree
|
||||||
featureFlags: FeatureFlags
|
featureFlags: FeatureFlags
|
||||||
page: {
|
page: {
|
||||||
|
documentType: string
|
||||||
languageVariants: Array<{ name: string; code: string; hreflang: string; href: string }>
|
languageVariants: Array<{ name: string; code: string; hreflang: string; href: string }>
|
||||||
topics: Array<string>
|
topics: Array<string>
|
||||||
fullTitle?: string
|
fullTitle?: string
|
||||||
@@ -104,7 +105,7 @@ export type MainContextT = {
|
|||||||
|
|
||||||
export const getMainContextFromRequest = (req: any): MainContextT => {
|
export const getMainContextFromRequest = (req: any): MainContextT => {
|
||||||
return {
|
return {
|
||||||
builtAssets: req.context.builtAssets,
|
builtAssets: { main: { js: req.context.builtAssets.main.js } },
|
||||||
expose: req.context.expose,
|
expose: req.context.expose,
|
||||||
breadcrumbs: req.context.breadcrumbs || {},
|
breadcrumbs: req.context.breadcrumbs || {},
|
||||||
activeProducts: req.context.activeProducts,
|
activeProducts: req.context.activeProducts,
|
||||||
@@ -126,6 +127,7 @@ export const getMainContextFromRequest = (req: any): MainContextT => {
|
|||||||
relativePath: req.context.page?.relativePath,
|
relativePath: req.context.page?.relativePath,
|
||||||
page: {
|
page: {
|
||||||
languageVariants: req.context.page.languageVariants,
|
languageVariants: req.context.page.languageVariants,
|
||||||
|
documentType: req.context.page.documentType,
|
||||||
fullTitle: req.context.page.fullTitle,
|
fullTitle: req.context.page.fullTitle,
|
||||||
topics: req.context.page.topics || [],
|
topics: req.context.page.topics || [],
|
||||||
introPlainText: req.context.page?.introPlainText,
|
introPlainText: req.context.page?.introPlainText,
|
||||||
|
|||||||
@@ -70,8 +70,9 @@ export const useProductLandingContext = (): ProductLandingContextT => {
|
|||||||
|
|
||||||
export const getProductLandingContextFromRequest = (req: any): ProductLandingContextT => {
|
export const getProductLandingContextFromRequest = (req: any): ProductLandingContextT => {
|
||||||
const productTree = req.context.currentProductTree
|
const productTree = req.context.currentProductTree
|
||||||
|
const page = req.context.page
|
||||||
return {
|
return {
|
||||||
...pick(req.context.page, [
|
...pick(page, [
|
||||||
'title',
|
'title',
|
||||||
'shortTitle',
|
'shortTitle',
|
||||||
'introPlainText',
|
'introPlainText',
|
||||||
@@ -96,11 +97,11 @@ export const getProductLandingContextFromRequest = (req: any): ProductLandingCon
|
|||||||
})
|
})
|
||||||
),
|
),
|
||||||
|
|
||||||
introLinks: productTree.page.introLinks
|
introLinks: page.introLinks
|
||||||
? {
|
? {
|
||||||
quickstart: productTree.page.introLinks.quickstart,
|
quickstart: page.introLinks.quickstart,
|
||||||
reference: productTree.page.introLinks.reference,
|
reference: page.introLinks.reference,
|
||||||
overview: productTree.page.introLinks.overview,
|
overview: page.introLinks.overview,
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
|
|
||||||
|
|||||||
33
components/context/TocLandingContext.tsx
Normal file
33
components/context/TocLandingContext.tsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { createContext, useContext } from 'react'
|
||||||
|
|
||||||
|
export type TocItem = {
|
||||||
|
fullPath: string
|
||||||
|
title: string
|
||||||
|
intro?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TocLandingContextT = {
|
||||||
|
title: string
|
||||||
|
introPlainText: string
|
||||||
|
tocItems: Array<TocItem>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TocLandingContext = createContext<TocLandingContextT | null>(null)
|
||||||
|
|
||||||
|
export const useTocLandingContext = (): TocLandingContextT => {
|
||||||
|
const context = useContext(TocLandingContext)
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
throw new Error('"useTocLandingContext" may only be used inside "TocLandingContext.Provider"')
|
||||||
|
}
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getTocLandingContextFromRequest = (req: any): TocLandingContextT => {
|
||||||
|
return {
|
||||||
|
title: req.context.page.title,
|
||||||
|
introPlainText: req.context.page.introPlainText,
|
||||||
|
tocItems: req.context.tocItems || [],
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import cx from 'classnames'
|
import cx from 'classnames'
|
||||||
import Link from 'next/link'
|
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
|
|
||||||
|
import { Link } from 'components/Link'
|
||||||
import { ArrowRightIcon } from '@primer/octicons-react'
|
import { ArrowRightIcon } from '@primer/octicons-react'
|
||||||
import { FeaturedLink, useProductLandingContext } from 'components/context/ProductLandingContext'
|
import { FeaturedLink, useProductLandingContext } from 'components/context/ProductLandingContext'
|
||||||
import { useTranslation } from 'components/hooks/useTranslation'
|
import { useTranslation } from 'components/hooks/useTranslation'
|
||||||
@@ -63,10 +63,8 @@ const ArticleList = ({ title, viewAllHref, articles }: ArticleListProps) => {
|
|||||||
<div className="featured-links-heading mb-4 d-flex flex-items-baseline">
|
<div className="featured-links-heading mb-4 d-flex flex-items-baseline">
|
||||||
<h3 className="f4 text-normal text-mono text-uppercase">{title}</h3>
|
<h3 className="f4 text-normal text-mono text-uppercase">{title}</h3>
|
||||||
{viewAllHref && (
|
{viewAllHref && (
|
||||||
<Link href={viewAllHref}>
|
<Link href={viewAllHref} className="ml-4">
|
||||||
<a className="ml-4">
|
View all <ArrowRightIcon size={14} className="v-align-middle" />
|
||||||
View all <ArrowRightIcon size={14} className="v-align-middle" />
|
|
||||||
</a>
|
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -75,30 +73,31 @@ const ArticleList = ({ title, viewAllHref, articles }: ArticleListProps) => {
|
|||||||
{articles.map((link, i) => {
|
{articles.map((link, i) => {
|
||||||
return (
|
return (
|
||||||
<li key={link.href} className="border-top">
|
<li key={link.href} className="border-top">
|
||||||
<Link href={link.href}>
|
<Link
|
||||||
<a className="link-with-intro Bump-link--hover no-underline d-block py-3">
|
href={link.href}
|
||||||
<h4 className="link-with-intro-title">
|
className="link-with-intro Bump-link--hover no-underline d-block py-3"
|
||||||
{link.title}
|
>
|
||||||
<span className="Bump-link-symbol">→</span>
|
<h4 className="link-with-intro-title">
|
||||||
</h4>
|
<span dangerouslySetInnerHTML={{ __html: link.title }} />
|
||||||
{!link.hideIntro && link.intro && (
|
<span className="Bump-link-symbol">→</span>
|
||||||
<TruncateLines
|
</h4>
|
||||||
as="p"
|
{!link.hideIntro && link.intro && (
|
||||||
maxLines={2}
|
<TruncateLines
|
||||||
className="link-with-intro-intro color-text-secondary mb-0 mt-1"
|
as="p"
|
||||||
>
|
maxLines={2}
|
||||||
{link.intro}
|
className="link-with-intro-intro color-text-secondary mb-0 mt-1"
|
||||||
</TruncateLines>
|
>
|
||||||
)}
|
<span dangerouslySetInnerHTML={{ __html: link.intro }} />
|
||||||
{link.date && (
|
</TruncateLines>
|
||||||
<time
|
)}
|
||||||
className="tooltipped tooltipped-n color-text-tertiary text-mono mt-1"
|
{link.date && (
|
||||||
aria-label={dayjs(link.date).format('LLL')}
|
<time
|
||||||
>
|
className="tooltipped tooltipped-n color-text-tertiary text-mono mt-1"
|
||||||
{dayjs(link.date).format('MMMM DD')}
|
aria-label={dayjs(link.date).format('LLL')}
|
||||||
</time>
|
>
|
||||||
)}
|
{dayjs(link.date).format('MMMM DD')}
|
||||||
</a>
|
</time>
|
||||||
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import Link from 'next/link'
|
|
||||||
|
|
||||||
|
import { Link } from 'components/Link'
|
||||||
import { ArrowRightIcon } from '@primer/octicons-react'
|
import { ArrowRightIcon } from '@primer/octicons-react'
|
||||||
import { useMainContext } from 'components/context/MainContext'
|
import { useMainContext } from 'components/context/MainContext'
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@ export const GuideCards = () => {
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { currentCategory } = useMainContext()
|
const { currentCategory } = useMainContext()
|
||||||
const { guideCards } = useProductLandingContext()
|
const { guideCards } = useProductLandingContext()
|
||||||
|
const routePath = `/${router.locale}${router.asPath.split('?')[0]}` // remove query string
|
||||||
|
|
||||||
if (!guideCards) {
|
if (!guideCards) {
|
||||||
return null
|
return null
|
||||||
@@ -25,10 +26,8 @@ export const GuideCards = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!currentCategory && (
|
{!currentCategory && (
|
||||||
<Link href={`${router.asPath}/guides`}>
|
<Link href={`${routePath}/guides`} className="btn btn-outline float-right">
|
||||||
<a className="btn btn-outline float-right">
|
Explore guides <ArrowRightIcon />
|
||||||
Explore guides <ArrowRightIcon />
|
|
||||||
</a>
|
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import Link from 'next/link'
|
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { Dropdown } from '@primer/components'
|
import { Dropdown } from '@primer/components'
|
||||||
|
|
||||||
|
import { Link } from 'components/Link'
|
||||||
import { useMainContext } from 'components/context/MainContext'
|
import { useMainContext } from 'components/context/MainContext'
|
||||||
import { useVersion } from 'components/hooks/useVersion'
|
import { useVersion } from 'components/hooks/useVersion'
|
||||||
import { useTranslation } from 'components/hooks/useTranslation'
|
import { useTranslation } from 'components/hooks/useTranslation'
|
||||||
@@ -41,17 +41,16 @@ export const HomepageVersionPicker = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown.Item key={permalink.href}>
|
<Dropdown.Item key={permalink.href}>
|
||||||
<Link href={permalink.href}>
|
<Link href={permalink.href}>{permalink.pageVersionTitle}</Link>
|
||||||
<a>{permalink.pageVersionTitle}</a>
|
|
||||||
</Link>
|
|
||||||
</Dropdown.Item>
|
</Dropdown.Item>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
<div className="pb-1">
|
<div className="pb-1">
|
||||||
<Link href={`/${router.locale}/${enterpriseServerVersions[0]}/admin/all-releases`}>
|
<Link
|
||||||
<a className="f6 no-underline color-text-tertiary pl-3 pr-2 no-wrap">
|
href={`/${router.locale}/${enterpriseServerVersions[0]}/admin/all-releases`}
|
||||||
See all Enterprise releases
|
className="f6 no-underline color-text-tertiary pl-3 pr-2 no-wrap"
|
||||||
</a>
|
>
|
||||||
|
See all Enterprise releases
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</Dropdown.Menu>
|
</Dropdown.Menu>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import cx from 'classnames'
|
import cx from 'classnames'
|
||||||
import Link from 'next/link'
|
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useMainContext } from 'components/context/MainContext'
|
import { useMainContext } from 'components/context/MainContext'
|
||||||
|
|
||||||
|
import { Link } from 'components/Link'
|
||||||
import { useProductLandingContext } from 'components/context/ProductLandingContext'
|
import { useProductLandingContext } from 'components/context/ProductLandingContext'
|
||||||
import { useTranslation } from 'components/hooks/useTranslation'
|
import { useTranslation } from 'components/hooks/useTranslation'
|
||||||
import { useVersion } from 'components/hooks/useVersion'
|
import { useVersion } from 'components/hooks/useVersion'
|
||||||
@@ -107,8 +107,8 @@ export const FullLink = ({ href, children, className }: Props) => {
|
|||||||
currentVersion !== 'free-pro-team@latest' ? `/${currentVersion}` : ''
|
currentVersion !== 'free-pro-team@latest' ? `/${currentVersion}` : ''
|
||||||
}${href}`
|
}${href}`
|
||||||
return (
|
return (
|
||||||
<Link href={fullyQualifiedHref}>
|
<Link href={fullyQualifiedHref} className={className}>
|
||||||
<a className={className}>{children}</a>
|
{children}
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import Link from 'next/link'
|
|
||||||
|
|
||||||
import cx from 'classnames'
|
import cx from 'classnames'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
|
||||||
import { ChevronUpIcon } from '@primer/octicons-react'
|
import { ChevronUpIcon } from '@primer/octicons-react'
|
||||||
|
|
||||||
import { CurrentProductTree, useMainContext } from 'components/context/MainContext'
|
import { CurrentProductTree, useMainContext } from 'components/context/MainContext'
|
||||||
|
import { Link } from 'components/Link'
|
||||||
|
|
||||||
const maxArticles = 10
|
const maxArticles = 10
|
||||||
|
|
||||||
@@ -33,9 +34,7 @@ const ArticleList = ({ page }: { page: CurrentProductTree }) => {
|
|||||||
return (
|
return (
|
||||||
<div className="col-12 col-lg-4 mb-6 height-full">
|
<div className="col-12 col-lg-4 mb-6 height-full">
|
||||||
<h4 className="mb-3">
|
<h4 className="mb-3">
|
||||||
<Link href={page.href}>
|
<Link href={page.href}>{page.page.title}</Link>
|
||||||
<a>{page.page.title}</a>
|
|
||||||
</Link>
|
|
||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
<ul className="list-style-none">
|
<ul className="list-style-none">
|
||||||
@@ -47,11 +46,9 @@ const ArticleList = ({ page }: { page: CurrentProductTree }) => {
|
|||||||
return (
|
return (
|
||||||
<li
|
<li
|
||||||
key={grandchildPage.href + index}
|
key={grandchildPage.href + index}
|
||||||
className={cx('mb-3', index >= maxArticles ? 'd-none' : null)}
|
className={cx('mb-3', !isShowingMore && index >= maxArticles ? 'd-none' : null)}
|
||||||
>
|
>
|
||||||
<Link href={grandchildPage.href}>
|
<Link href={grandchildPage.href}>{grandchildPage.page.title}</Link>
|
||||||
<a>{grandchildPage.page.title}</a>
|
|
||||||
</Link>
|
|
||||||
{grandchildPage.page.documentType === 'mapTopic' ? (
|
{grandchildPage.page.documentType === 'mapTopic' ? (
|
||||||
<small className="color-text-secondary d-inline-block">
|
<small className="color-text-secondary d-inline-block">
|
||||||
• {page.childPages.length} articles
|
• {page.childPages.length} articles
|
||||||
|
|||||||
69
components/landing/ProductLanding.tsx
Normal file
69
components/landing/ProductLanding.tsx
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import { DefaultLayout } from 'components/DefaultLayout'
|
||||||
|
import { useProductLandingContext } from 'components/context/ProductLandingContext'
|
||||||
|
|
||||||
|
import { LandingHero } from 'components/landing/LandingHero'
|
||||||
|
import { FeaturedArticles } from 'components/landing/FeaturedArticles'
|
||||||
|
import { GuideCards } from 'components/landing/GuideCards'
|
||||||
|
import { SponsorsExamples } from 'components/landing/SponsorsExamples'
|
||||||
|
import { CommunityExamples } from 'components/landing/CommunityExamples'
|
||||||
|
import { CodeExamples } from 'components/landing/CodeExamples'
|
||||||
|
import { LandingSection } from 'components/landing/LandingSection'
|
||||||
|
import { useTranslation } from 'components/hooks/useTranslation'
|
||||||
|
import { ProductArticlesList } from 'components/landing/ProductArticlesList'
|
||||||
|
|
||||||
|
export const ProductLanding = () => {
|
||||||
|
const {
|
||||||
|
shortTitle,
|
||||||
|
guideCards,
|
||||||
|
productUserExamples,
|
||||||
|
productCommunityExamples,
|
||||||
|
productCodeExamples,
|
||||||
|
} = useProductLandingContext()
|
||||||
|
const { t } = useTranslation('product_landing')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DefaultLayout>
|
||||||
|
<LandingSection className="pt-3">
|
||||||
|
<LandingHero />
|
||||||
|
</LandingSection>
|
||||||
|
|
||||||
|
<LandingSection>
|
||||||
|
<FeaturedArticles />
|
||||||
|
</LandingSection>
|
||||||
|
|
||||||
|
{productCodeExamples.length > 0 && (
|
||||||
|
<LandingSection title={t('code_examples')} className="my-6">
|
||||||
|
<CodeExamples />
|
||||||
|
</LandingSection>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{productCommunityExamples.length > 0 && (
|
||||||
|
<LandingSection title={t('communities_using_discussions')} className="my-6">
|
||||||
|
<CommunityExamples />
|
||||||
|
</LandingSection>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{productUserExamples.length > 0 && (
|
||||||
|
<LandingSection title={t('sponsor_community')} className="my-6">
|
||||||
|
<SponsorsExamples />
|
||||||
|
</LandingSection>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* {% if currentVersion contains 'enterprise-server' and currentProduct == 'admin' %}
|
||||||
|
{% include product-releases %}
|
||||||
|
{% endif %} */}
|
||||||
|
|
||||||
|
{guideCards.length > 0 && (
|
||||||
|
<div className="color-bg-tertiary py-6 my-8">
|
||||||
|
<LandingSection title={t('guides')} className="my-6">
|
||||||
|
<GuideCards />
|
||||||
|
</LandingSection>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<LandingSection sectionLink="all-docs" title={`All ${shortTitle} Docs`}>
|
||||||
|
<ProductArticlesList />
|
||||||
|
</LandingSection>
|
||||||
|
</DefaultLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import Link from 'next/link'
|
|
||||||
import { ArrowRightIcon } from '@primer/octicons-react'
|
import { ArrowRightIcon } from '@primer/octicons-react'
|
||||||
|
|
||||||
|
import { Link } from 'components/Link'
|
||||||
import { useProductLandingContext } from 'components/context/ProductLandingContext'
|
import { useProductLandingContext } from 'components/context/ProductLandingContext'
|
||||||
import { useTranslation } from 'components/hooks/useTranslation'
|
import { useTranslation } from 'components/hooks/useTranslation'
|
||||||
import { UserCard } from 'components/landing/UserCard'
|
import { UserCard } from 'components/landing/UserCard'
|
||||||
@@ -24,10 +24,8 @@ export const SponsorsExamples = () => {
|
|||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<Link href={`https://github.com/sponsors/community`}>
|
<Link href={`https://github.com/sponsors/community`} className="btn btn-outline float-right">
|
||||||
<a className="btn btn-outline float-right">
|
{t('explore_people_and_projects')} <ArrowRightIcon />
|
||||||
{t('explore_people_and_projects')} <ArrowRightIcon />
|
|
||||||
</a>
|
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,34 +1,45 @@
|
|||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import Link from 'next/link'
|
|
||||||
import cx from 'classnames'
|
import cx from 'classnames'
|
||||||
|
|
||||||
import type { TocItem } from '../context/ProductLandingContext'
|
import { Link } from 'components/Link'
|
||||||
|
import type { TocItem } from 'components/context/ProductLandingContext'
|
||||||
|
|
||||||
export const TableOfContents = (props: { items?: Array<TocItem> }) => {
|
type Props = {
|
||||||
|
items: Array<TocItem>
|
||||||
|
variant?: 'compact' | 'expanded'
|
||||||
|
}
|
||||||
|
export const TableOfContents = (props: Props) => {
|
||||||
|
const { items, variant = 'expanded' } = props
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<ul className={cx(variant === 'compact' ? 'list-style-inside pl-2' : 'list-style-none')}>
|
||||||
{(props.items || []).map((obj) => {
|
{(items || []).map((item) => {
|
||||||
if (!obj) {
|
if (!item) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
const { fullPath: href, title, intro } = obj
|
|
||||||
|
const { fullPath: href, title, intro } = item
|
||||||
const isActive = router.pathname === href
|
const isActive = router.pathname === href
|
||||||
return (
|
return variant === 'compact' ? (
|
||||||
<div key={href} className={cx('mb-5', isActive && 'color-auto-gray-4')}>
|
<li key={href} className="f4 my-1">
|
||||||
<Link href={href}>
|
<Link href={href}>{title}</Link>
|
||||||
<a className="Bump-link--hover no-underline d-block py-1 border-bottom color-border-primary">
|
</li>
|
||||||
<h4>
|
) : (
|
||||||
{title}
|
<li key={href} className={cx('mb-5', isActive && 'color-auto-gray-4')}>
|
||||||
<span className="Bump-link-symbol">→</span>
|
<Link
|
||||||
</h4>
|
href={href}
|
||||||
</a>
|
className="Bump-link--hover no-underline d-block py-1 border-bottom color-border-primary"
|
||||||
|
>
|
||||||
|
<h4>
|
||||||
|
{title}
|
||||||
|
<span className="Bump-link-symbol">→</span>
|
||||||
|
</h4>
|
||||||
</Link>
|
</Link>
|
||||||
{intro && <p className="f4 mt-3" dangerouslySetInnerHTML={{ __html: intro }} />}
|
{intro && <p className="f4 mt-3" dangerouslySetInnerHTML={{ __html: intro }} />}
|
||||||
</div>
|
</li>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</ul>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
55
components/landing/TocLanding.tsx
Normal file
55
components/landing/TocLanding.tsx
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import { Grid } from '@primer/components'
|
||||||
|
|
||||||
|
import { DefaultLayout } from 'components/DefaultLayout'
|
||||||
|
import { TableOfContents } from 'components/landing/TableOfContents'
|
||||||
|
import { ArticleVersionPicker } from 'components/article/ArticleVersionPicker'
|
||||||
|
import { Breadcrumbs } from 'components/Breadcrumbs'
|
||||||
|
import { useTocLandingContext } from 'components/context/TocLandingContext'
|
||||||
|
import { ArticleTitle } from 'components/article/ArticleTitle'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
variant?: 'compact' | 'expanded'
|
||||||
|
}
|
||||||
|
export const TocLanding = ({ variant = 'expanded' }: Props) => {
|
||||||
|
const { title, introPlainText, tocItems } = useTocLandingContext()
|
||||||
|
return (
|
||||||
|
<DefaultLayout>
|
||||||
|
<div className="container-xl px-3 px-md-6 my-4 my-lg-4">
|
||||||
|
<div className="d-lg-flex flex-justify-between">
|
||||||
|
<div className="d-block d-lg-none">
|
||||||
|
<ArticleVersionPicker />
|
||||||
|
</div>
|
||||||
|
<div className="d-flex flex-items-center">
|
||||||
|
<Breadcrumbs />
|
||||||
|
</div>
|
||||||
|
<div className="d-none d-lg-block">
|
||||||
|
<ArticleVersionPicker />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Grid
|
||||||
|
gridTemplateColumns="minmax(500px, 720px) minmax(220px, 1fr)"
|
||||||
|
gridTemplateRows="auto 1fr"
|
||||||
|
gridGap={16}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div className="mt-8">
|
||||||
|
<ArticleTitle>{title}</ArticleTitle>
|
||||||
|
|
||||||
|
<div className="lead-mktg">
|
||||||
|
<p>{introPlainText}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="border-bottom border-xl-0 pb-4 mb-5 pb-xl-0 mb-xl-0" />
|
||||||
|
|
||||||
|
<div className={variant === 'expanded' ? 'mt-7' : 'mt-2'}>
|
||||||
|
<TableOfContents items={tocItems} variant={variant} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div></div>
|
||||||
|
</Grid>
|
||||||
|
</div>
|
||||||
|
</DefaultLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,16 +1,12 @@
|
|||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import Link from 'next/link'
|
|
||||||
import cx from 'classnames'
|
import cx from 'classnames'
|
||||||
|
import { useDetails, Details } from '@primer/components'
|
||||||
|
import { ChevronDownIcon } from '@primer/octicons-react'
|
||||||
|
|
||||||
import { useMainContext } from 'components/context/MainContext'
|
import { Link } from 'components/Link'
|
||||||
|
import { CurrentProductTree, useMainContext } from 'components/context/MainContext'
|
||||||
import { AllProductsLink } from 'components/product/AllProductsLink'
|
import { AllProductsLink } from 'components/product/AllProductsLink'
|
||||||
// <!--
|
|
||||||
// Styling note:
|
|
||||||
|
|
||||||
// Categories, Maptopics, and Articles list items get a class of `active` when they correspond to content
|
|
||||||
// hierarchy of the current page. If an item's URL is also the same as the current URL, the item
|
|
||||||
// also gets an `is-current-page` class.
|
|
||||||
// -->
|
|
||||||
export const SidebarProduct = () => {
|
export const SidebarProduct = () => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { currentProductTree: currentProductTree } = useMainContext()
|
const { currentProductTree: currentProductTree } = useMainContext()
|
||||||
@@ -28,8 +24,11 @@ export const SidebarProduct = () => {
|
|||||||
{!currentProductTree.page.hidden && (
|
{!currentProductTree.page.hidden && (
|
||||||
<>
|
<>
|
||||||
<li title="" className="sidebar-product mb-2">
|
<li title="" className="sidebar-product mb-2">
|
||||||
<Link href={currentProductTree.href}>
|
<Link
|
||||||
<a className="pl-4 pr-5 pb-1 f4 color-text-primary">{productTitle}</a>
|
href={currentProductTree.href}
|
||||||
|
className="pl-4 pr-5 pb-1 f4 color-text-primary no-underline"
|
||||||
|
>
|
||||||
|
{productTitle}
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
@@ -52,136 +51,19 @@ export const SidebarProduct = () => {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{isStandaloneCategory ? (
|
{isStandaloneCategory ? (
|
||||||
<Link href={childPage.href}>
|
<Link
|
||||||
<a className="pl-4 pr-2 py-2 f6 text-uppercase d-block flex-auto mr-3 color-text-primary">
|
href={childPage.href}
|
||||||
{childTitle}
|
className="pl-4 pr-2 py-2 f6 text-uppercase d-block flex-auto mr-3 color-text-primary no-underline"
|
||||||
</a>
|
>
|
||||||
|
{childTitle}
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
<details
|
<CollapsibleSection
|
||||||
className={cx('dropdown-withArrow details details-reset')}
|
index={i}
|
||||||
open={routePath.includes(childPage.href) || i < 3}
|
routePath={routePath}
|
||||||
>
|
title={childTitle}
|
||||||
<summary>
|
page={childPage}
|
||||||
<div className="d-flex flex-justify-between">
|
/>
|
||||||
<Link href={childPage.href}>
|
|
||||||
<a className="pl-4 pr-2 py-2 f6 text-uppercase d-block flex-auto mr-3 color-text-primary">
|
|
||||||
{childTitle}
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
{i < 3 && (
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
className="octicon flex-shrink-0 arrow mr-3"
|
|
||||||
style={{ marginTop: 7 }}
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
>
|
|
||||||
{' '}
|
|
||||||
<path
|
|
||||||
fillRule="evenodd"
|
|
||||||
clipRule="evenodd"
|
|
||||||
d="M12.7803 6.21967C13.0732 6.51256 13.0732 6.98744 12.7803 7.28033L8.53033 11.5303C8.23744 11.8232 7.76256 11.8232 7.46967 11.5303L3.21967 7.28033C2.92678 6.98744 2.92678 6.51256 3.21967 6.21967C3.51256 5.92678 3.98744 5.92678 4.28033 6.21967L8 9.93934L11.7197 6.21967C12.0126 5.92678 12.4874 5.92678 12.7803 6.21967Z"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</summary>
|
|
||||||
{routePath.includes(childPage.href) || i < 3 ? (
|
|
||||||
<>
|
|
||||||
{/* <!-- some categories have maptopics with child articles --> */}
|
|
||||||
{childPage.childPages[0].page.documentType === 'mapTopic' ? (
|
|
||||||
<ul className="sidebar-topics list-style-none position-relative">
|
|
||||||
{childPage.childPages.map((grandchildPage, i) => {
|
|
||||||
const grandchildTitle =
|
|
||||||
grandchildPage.renderedShortTitle ||
|
|
||||||
grandchildPage.renderedFullTitle
|
|
||||||
const isActive = routePath.includes(grandchildPage.href)
|
|
||||||
const isCurrent = routePath === grandchildPage.href
|
|
||||||
return (
|
|
||||||
<li
|
|
||||||
key={childPage.href + i}
|
|
||||||
className={cx(
|
|
||||||
'sidebar-maptopic',
|
|
||||||
isActive && 'active',
|
|
||||||
isCurrent && 'is-current-page'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Link href={grandchildPage.href}>
|
|
||||||
<a className="pl-4 pr-5 py-2 color-text-primary">{grandchildTitle}</a>
|
|
||||||
</Link>
|
|
||||||
<ul className="sidebar-articles my-2">
|
|
||||||
{grandchildPage.childPages.map(
|
|
||||||
(greatgrandchildPage, i, arr) => {
|
|
||||||
const greatgrandchildTitle =
|
|
||||||
greatgrandchildPage.renderedShortTitle ||
|
|
||||||
greatgrandchildPage.renderedFullTitle
|
|
||||||
const isLast = i === arr.length - 1
|
|
||||||
const isActive = routePath.includes(
|
|
||||||
greatgrandchildPage.href
|
|
||||||
)
|
|
||||||
const isCurrent = routePath === greatgrandchildPage.href
|
|
||||||
return (
|
|
||||||
<li
|
|
||||||
key={greatgrandchildPage.href + i}
|
|
||||||
className={cx(
|
|
||||||
'sidebar-article',
|
|
||||||
isActive && 'active',
|
|
||||||
isCurrent && 'is-current-page'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Link href={greatgrandchildPage.href}>
|
|
||||||
<a
|
|
||||||
className={cx(
|
|
||||||
'pl-6 pr-5 py-1 color-text-primary',
|
|
||||||
isLast && 'pb-2'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{greatgrandchildTitle}
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
) : childPage.childPages[0].page.documentType == 'article' ? (
|
|
||||||
<ul className="sidebar-articles list-style-none">
|
|
||||||
{/* <!-- some categories have no maptopics, only articles --> */}
|
|
||||||
{childPage.childPages.map((grandchildPage, i, arr) => {
|
|
||||||
const grandchildTitle =
|
|
||||||
grandchildPage.renderedShortTitle ||
|
|
||||||
grandchildPage.renderedFullTitle
|
|
||||||
const isLast = i === arr.length - 1
|
|
||||||
const isActive = routePath.includes(grandchildPage.href)
|
|
||||||
const isCurrent = routePath === grandchildPage.href
|
|
||||||
return (
|
|
||||||
<li
|
|
||||||
key={grandchildPage.href + i}
|
|
||||||
className={cx(
|
|
||||||
'sidebar-article',
|
|
||||||
isActive && 'active',
|
|
||||||
isCurrent && 'is-current-page'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Link href={grandchildPage.href}>
|
|
||||||
<a className={cx('pl-6 pr-5 py-1 color-text-primary', isLast && 'pb-2')}>
|
|
||||||
{grandchildTitle}
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
) : null}
|
|
||||||
</>
|
|
||||||
) : null}
|
|
||||||
</details>
|
|
||||||
)}
|
)}
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
@@ -193,3 +75,117 @@ export const SidebarProduct = () => {
|
|||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SectionProps = {
|
||||||
|
index: number
|
||||||
|
routePath: string
|
||||||
|
page: CurrentProductTree
|
||||||
|
title: string
|
||||||
|
}
|
||||||
|
const CollapsibleSection = (props: SectionProps) => {
|
||||||
|
const { routePath, index, title, page } = props
|
||||||
|
const isDefaultOpen = routePath.includes(page.href) || index < 3
|
||||||
|
const { getDetailsProps, open: isOpen } = useDetails({ defaultOpen: isDefaultOpen })
|
||||||
|
return (
|
||||||
|
<Details {...getDetailsProps()} className="details-reset">
|
||||||
|
<summary>
|
||||||
|
<div className="d-flex flex-justify-between">
|
||||||
|
<Link
|
||||||
|
href={page.href}
|
||||||
|
className="pl-4 pr-2 py-2 f6 text-uppercase d-block flex-auto mr-3 color-text-primary no-underline"
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</Link>
|
||||||
|
{page.childPages.length > 0 && (
|
||||||
|
<span style={{ marginTop: 7 }} className="flex-shrink-0 pr-3">
|
||||||
|
<ChevronDownIcon className={cx('opacity-60', isOpen && 'rotate-180')} />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</summary>
|
||||||
|
{/* <!-- some categories have maptopics with child articles --> */}
|
||||||
|
{page.childPages[0].page.documentType === 'mapTopic' ? (
|
||||||
|
<ul className="sidebar-topics list-style-none position-relative">
|
||||||
|
{page.childPages.map((childPage, i) => {
|
||||||
|
const childTitle = childPage.renderedShortTitle || childPage.renderedFullTitle
|
||||||
|
const isActive = routePath.includes(childPage.href)
|
||||||
|
const isCurrent = routePath === childPage.href
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
key={childPage.href + i}
|
||||||
|
className={cx(
|
||||||
|
'sidebar-maptopic',
|
||||||
|
isActive && 'active',
|
||||||
|
isCurrent && 'is-current-page'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
href={childPage.href}
|
||||||
|
className="pl-4 pr-5 py-2 color-text-primary no-underline"
|
||||||
|
>
|
||||||
|
{childTitle}
|
||||||
|
</Link>
|
||||||
|
<ul className="sidebar-articles my-2">
|
||||||
|
{childPage.childPages.map((grandchildPage, i, arr) => {
|
||||||
|
const grandchildTitle =
|
||||||
|
grandchildPage.renderedShortTitle || grandchildPage.renderedFullTitle
|
||||||
|
const isLast = i === arr.length - 1
|
||||||
|
const isActive = routePath.includes(grandchildPage.href)
|
||||||
|
const isCurrent = routePath === grandchildPage.href
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
key={grandchildPage.href + i}
|
||||||
|
className={cx(
|
||||||
|
'sidebar-article',
|
||||||
|
isActive && 'active',
|
||||||
|
isCurrent && 'is-current-page'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
href={grandchildPage.href}
|
||||||
|
className={cx(
|
||||||
|
'pl-6 pr-5 py-1 color-text-primary no-underline',
|
||||||
|
isLast && 'pb-2'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{grandchildTitle}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
) : page.childPages[0].page.documentType == 'article' ? (
|
||||||
|
<ul className="sidebar-articles list-style-none">
|
||||||
|
{/* <!-- some categories have no maptopics, only articles --> */}
|
||||||
|
{page.childPages.map((childPage, i, arr) => {
|
||||||
|
const childTitle = childPage.renderedShortTitle || childPage.renderedFullTitle
|
||||||
|
const isLast = i === arr.length - 1
|
||||||
|
const isActive = routePath.includes(childPage.href)
|
||||||
|
const isCurrent = routePath === childPage.href
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
key={childPage.href + i}
|
||||||
|
className={cx(
|
||||||
|
'sidebar-article',
|
||||||
|
isActive && 'active',
|
||||||
|
isCurrent && 'is-current-page'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
href={childPage.href}
|
||||||
|
className={cx('pl-6 pr-5 py-1 color-text-primary no-underline', isLast && 'pb-2')}
|
||||||
|
>
|
||||||
|
{childTitle}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
) : null}
|
||||||
|
</Details>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,13 +35,13 @@ Once you complete this project, you should understand how to build your own Java
|
|||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
Before you begin, you'll need to download Node.js and create a GitHub repository.
|
Before you begin, you'll need to download Node.js and create a public {% data variables.product.prodname_dotcom %} repository.
|
||||||
|
|
||||||
1. Download and install Node.js 12.x, which includes npm.
|
1. Download and install Node.js 12.x, which includes npm.
|
||||||
|
|
||||||
https://nodejs.org/en/download/current/
|
https://nodejs.org/en/download/current/
|
||||||
|
|
||||||
1. Create a new repository on {% data variables.product.product_location %}. You can choose any repository name or use "hello-world-javascript-action" like this example. You can add these files after your project has been pushed to {% data variables.product.product_name %}. For more information, see "[Create a new repository](/articles/creating-a-new-repository)."
|
1. Create a new public repository on {% data variables.product.product_location %} and call it "hello-world-javascript-action". For more information, see "[Create a new repository](/articles/creating-a-new-repository)."
|
||||||
|
|
||||||
1. Clone your repository to your computer. For more information, see "[Cloning a repository](/articles/cloning-a-repository)."
|
1. Clone your repository to your computer. For more information, see "[Cloning a repository](/articles/cloning-a-repository)."
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ Before you begin, you'll need to download Node.js and create a GitHub repository
|
|||||||
cd hello-world-javascript-action
|
cd hello-world-javascript-action
|
||||||
```
|
```
|
||||||
|
|
||||||
1. From your terminal, initialize the directory with a `package.json` file.
|
1. From your terminal, initialize the directory with npm to generate a `package.json` file.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
npm init -y
|
npm init -y
|
||||||
@@ -59,10 +59,8 @@ Before you begin, you'll need to download Node.js and create a GitHub repository
|
|||||||
|
|
||||||
### Creating an action metadata file
|
### Creating an action metadata file
|
||||||
|
|
||||||
Create a new file `action.yml` in the `hello-world-javascript-action` directory with the following example code. For more information, see "[Metadata syntax for {% data variables.product.prodname_actions %}](/actions/creating-actions/metadata-syntax-for-github-actions)."
|
Create a new file named `action.yml` in the `hello-world-javascript-action` directory with the following example code. For more information, see "[Metadata syntax for {% data variables.product.prodname_actions %}](/actions/creating-actions/metadata-syntax-for-github-actions)."
|
||||||
|
|
||||||
|
|
||||||
**action.yml**
|
|
||||||
```yaml
|
```yaml
|
||||||
name: 'Hello World'
|
name: 'Hello World'
|
||||||
description: 'Greet someone and record the time'
|
description: 'Greet someone and record the time'
|
||||||
@@ -108,7 +106,7 @@ GitHub Actions provide context information about the webhook event, Git refs, wo
|
|||||||
|
|
||||||
Add a new file called `index.js`, with the following code.
|
Add a new file called `index.js`, with the following code.
|
||||||
|
|
||||||
**index.js**
|
{% raw %}
|
||||||
```javascript
|
```javascript
|
||||||
const core = require('@actions/core');
|
const core = require('@actions/core');
|
||||||
const github = require('@actions/github');
|
const github = require('@actions/github');
|
||||||
@@ -126,6 +124,7 @@ try {
|
|||||||
core.setFailed(error.message);
|
core.setFailed(error.message);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
{% endraw %}
|
||||||
|
|
||||||
If an error is thrown in the above `index.js` example, `core.setFailed(error.message);` uses the actions toolkit [`@actions/core`](https://github.com/actions/toolkit/tree/main/packages/core) package to log a message and set a failing exit code. For more information, see "[Setting exit codes for actions](/actions/creating-actions/setting-exit-codes-for-actions)."
|
If an error is thrown in the above `index.js` example, `core.setFailed(error.message);` uses the actions toolkit [`@actions/core`](https://github.com/actions/toolkit/tree/main/packages/core) package to log a message and set a failing exit code. For more information, see "[Setting exit codes for actions](/actions/creating-actions/setting-exit-codes-for-actions)."
|
||||||
|
|
||||||
@@ -143,7 +142,6 @@ In your `hello-world-javascript-action` directory, create a `README.md` file tha
|
|||||||
- Environment variables the action uses.
|
- Environment variables the action uses.
|
||||||
- An example of how to use your action in a workflow.
|
- An example of how to use your action in a workflow.
|
||||||
|
|
||||||
**README.md**
|
|
||||||
```markdown
|
```markdown
|
||||||
# Hello world javascript action
|
# Hello world javascript action
|
||||||
|
|
||||||
@@ -180,7 +178,7 @@ It's best practice to also add a version tag for releases of your action. For mo
|
|||||||
```shell
|
```shell
|
||||||
git add action.yml index.js node_modules/* package.json package-lock.json README.md
|
git add action.yml index.js node_modules/* package.json package-lock.json README.md
|
||||||
git commit -m "My first action is ready"
|
git commit -m "My first action is ready"
|
||||||
git tag -a -m "My first action release" v1
|
git tag -a -m "My first action release" v1.1
|
||||||
git push --follow-tags
|
git push --follow-tags
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -205,7 +203,7 @@ Checking in your `node_modules` directory can cause problems. As an alternative,
|
|||||||
```shell
|
```shell
|
||||||
git add action.yml dist/index.js node_modules/*
|
git add action.yml dist/index.js node_modules/*
|
||||||
git commit -m "Use vercel/ncc"
|
git commit -m "Use vercel/ncc"
|
||||||
git tag -a -m "My first action release" v1
|
git tag -a -m "My first action release" v1.1
|
||||||
git push --follow-tags
|
git push --follow-tags
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -217,10 +215,11 @@ Now you're ready to test your action out in a workflow. When an action is in a p
|
|||||||
|
|
||||||
#### Example using a public action
|
#### Example using a public action
|
||||||
|
|
||||||
The following workflow code uses the completed hello world action in the `actions/hello-world-javascript-action` repository. Copy the workflow code into a `.github/workflows/main.yml` file, but replace the `actions/hello-world-javascript-action` repository with the repository you created. You can also replace the `who-to-greet` input with your name.
|
This example demonstrates how your new public action can be run from within an external repository.
|
||||||
|
|
||||||
|
Copy the following YAML into a new file at `.github/workflows/main.yml`, and update the `uses: octocat/hello-world-javascript-action@v1.1` line with your username and the name of the public repository you created above. You can also replace the `who-to-greet` input with your name.
|
||||||
|
|
||||||
{% raw %}
|
{% raw %}
|
||||||
**.github/workflows/main.yml**
|
|
||||||
```yaml
|
```yaml
|
||||||
on: [push]
|
on: [push]
|
||||||
|
|
||||||
@@ -231,7 +230,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Hello world action step
|
- name: Hello world action step
|
||||||
id: hello
|
id: hello
|
||||||
uses: actions/hello-world-javascript-action@v1.1
|
uses: octocat/hello-world-javascript-action@v1.1
|
||||||
with:
|
with:
|
||||||
who-to-greet: 'Mona the Octocat'
|
who-to-greet: 'Mona the Octocat'
|
||||||
# Use the output from the `hello` step
|
# Use the output from the `hello` step
|
||||||
@@ -240,6 +239,8 @@ jobs:
|
|||||||
```
|
```
|
||||||
{% endraw %}
|
{% endraw %}
|
||||||
|
|
||||||
|
When this workflow is triggered, the runner will download the `hello-world-javascript-action` action from your public repository and then execute it.
|
||||||
|
|
||||||
#### Example using a private action
|
#### Example using a private action
|
||||||
|
|
||||||
Copy the workflow code into a `.github/workflows/main.yml` file in your action's repository. You can also replace the `who-to-greet` input with your name.
|
Copy the workflow code into a `.github/workflows/main.yml` file in your action's repository. You can also replace the `who-to-greet` input with your name.
|
||||||
|
|||||||
@@ -10,6 +10,13 @@ versions:
|
|||||||
topics:
|
topics:
|
||||||
- Enterprise
|
- Enterprise
|
||||||
---
|
---
|
||||||
|
|
||||||
|
{% note %}
|
||||||
|
|
||||||
|
**Note:** Support for {% data variables.product.prodname_ghe_server %} on XenServer will be discontinued in {% data variables.product.prodname_ghe_server %} 3.3. For more information, see the [{% data variables.product.prodname_ghe_server %} 3.1 release notes](/admin/release-notes#3.1.0)
|
||||||
|
|
||||||
|
{% endnote %}
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
- {% data reusables.enterprise_installation.software-license %}
|
- {% data reusables.enterprise_installation.software-license %}
|
||||||
|
|||||||
@@ -2,13 +2,14 @@
|
|||||||
title: Viewing your subscriptions and billing date
|
title: Viewing your subscriptions and billing date
|
||||||
intro: 'You can view your account''s subscription, your other paid features and products, and your next billing date in your account''s billing settings.'
|
intro: 'You can view your account''s subscription, your other paid features and products, and your next billing date in your account''s billing settings.'
|
||||||
redirect_from:
|
redirect_from:
|
||||||
|
- /github/setting-up-and-managing-billing-and-payments-on-github/managing-your-github-billing-settings/viewing-your-subscriptions-and-billing-date
|
||||||
- /github/setting-up-and-managing-billing-and-payments-on-github/viewing-your-subscriptions-and-billing-date
|
- /github/setting-up-and-managing-billing-and-payments-on-github/viewing-your-subscriptions-and-billing-date
|
||||||
- /articles/finding-your-next-billing-date/
|
- /articles/finding-your-next-billing-date/
|
||||||
- /articles/finding-your-personal-account-s-next-billing-date/
|
- /articles/finding-your-personal-account-s-next-billing-date/
|
||||||
- /articles/finding-your-organization-s-next-billing-date/
|
- /articles/finding-your-organization-s-next-billing-date/
|
||||||
- /articles/viewing-your-plans-and-billing-date/
|
- /articles/viewing-your-plans-and-billing-date/
|
||||||
- /articles/viewing-your-subscriptions-and-billing-date
|
- /articles/viewing-your-subscriptions-and-billing-date
|
||||||
- /github/setting-up-and-managing-billing-and-payments-on-github/viewing-your-subscriptions-and-billing-date
|
|
||||||
versions:
|
versions:
|
||||||
free-pro-team: '*'
|
free-pro-team: '*'
|
||||||
type: how_to
|
type: how_to
|
||||||
|
|||||||
@@ -81,6 +81,18 @@ For more information about the `pull_request` event, see "[Workflow syntax for {
|
|||||||
|
|
||||||
If you scan pull requests, then the results appear as alerts in a pull request check. For more information, see "[Triaging code scanning alerts in pull requests](/code-security/secure-coding/triaging-code-scanning-alerts-in-pull-requests)."
|
If you scan pull requests, then the results appear as alerts in a pull request check. For more information, see "[Triaging code scanning alerts in pull requests](/code-security/secure-coding/triaging-code-scanning-alerts-in-pull-requests)."
|
||||||
|
|
||||||
|
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.1" or currentVersion == "github-ae@next" %}
|
||||||
|
#### Defining the alert severities causing pull request check failure
|
||||||
|
|
||||||
|
By default, only alerts with the severity level of `error` will cause a pull request check failure, and a check will still succeed with alerts of lower severities. You can change the levels of alert severities that will cause a pull request check failure in your repository settings.
|
||||||
|
|
||||||
|
{% data reusables.repositories.navigate-to-repo %}
|
||||||
|
{% data reusables.repositories.sidebar-settings %}
|
||||||
|
{% data reusables.repositories.navigate-to-security-and-analysis %}
|
||||||
|
1. Under "Code scanning", to the right of "Check Failure", use the drop-down menu to select the level of severity you would like to cause a pull request check failure.
|
||||||
|

|
||||||
|
{% endif %}
|
||||||
|
|
||||||
#### Avoiding unnecessary scans of pull requests
|
#### Avoiding unnecessary scans of pull requests
|
||||||
|
|
||||||
You might want to avoid a code scan being triggered on specific pull requests targeted against the default branch, irrespective of which files have been changed. You can configure this by specifying `on:pull_request:paths-ignore` or `on:pull_request:paths` in the {% data variables.product.prodname_code_scanning %} workflow. For example, if the only changes in a pull request are to files with the file extensions `.md` or `.txt` you can use the following `paths-ignore` array.
|
You might want to avoid a code scan being triggered on specific pull requests targeted against the default branch, irrespective of which files have been changed. You can configure this by specifying `on:pull_request:paths-ignore` or `on:pull_request:paths` in the {% data variables.product.prodname_code_scanning %} workflow. For example, if the only changes in a pull request are to files with the file extensions `.md` or `.txt` you can use the following `paths-ignore` array.
|
||||||
|
|||||||
@@ -27,7 +27,11 @@ topics:
|
|||||||
|
|
||||||
In repositories where {% data variables.product.prodname_code_scanning %} is configured as a pull request check, {% data variables.product.prodname_code_scanning %} checks the code in the pull request. By default, this is limited to pull requests that target the default branch, but you can change this configuration within {% data variables.product.prodname_actions %} or in a third-party CI/CD system. If merging the changes would introduce new {% data variables.product.prodname_code_scanning %} alerts to the target branch, these are reported as check results in the pull request. The alerts are also shown as annotations in the **Files changed** tab of the pull request. If you have write permission for the repository, you can see any existing {% data variables.product.prodname_code_scanning %} alerts on the **Security** tab. For information about repository alerts, see "[Managing {% data variables.product.prodname_code_scanning %} alerts for your repository](/code-security/secure-coding/managing-code-scanning-alerts-for-your-repository)."
|
In repositories where {% data variables.product.prodname_code_scanning %} is configured as a pull request check, {% data variables.product.prodname_code_scanning %} checks the code in the pull request. By default, this is limited to pull requests that target the default branch, but you can change this configuration within {% data variables.product.prodname_actions %} or in a third-party CI/CD system. If merging the changes would introduce new {% data variables.product.prodname_code_scanning %} alerts to the target branch, these are reported as check results in the pull request. The alerts are also shown as annotations in the **Files changed** tab of the pull request. If you have write permission for the repository, you can see any existing {% data variables.product.prodname_code_scanning %} alerts on the **Security** tab. For information about repository alerts, see "[Managing {% data variables.product.prodname_code_scanning %} alerts for your repository](/code-security/secure-coding/managing-code-scanning-alerts-for-your-repository)."
|
||||||
|
|
||||||
If {% data variables.product.prodname_code_scanning %} has any results with a severity of `error`, the check fails and the error is reported in the check results. If all the results found by {% data variables.product.prodname_code_scanning %} have lower severities, the alerts are treated as warnings or notices and the check succeeds. If your pull request targets a protected branch that uses {% data variables.product.prodname_code_scanning %}, and the repository owner has configured required status checks, then you must either fix or dismiss all error alerts before the pull request can be merged. For more information, see "[About protected branches](/github/administering-a-repository/about-protected-branches#require-status-checks-before-merging)."
|
If {% data variables.product.prodname_code_scanning %} has any results with a severity of `error`, the check fails and the error is reported in the check results. If all the results found by {% data variables.product.prodname_code_scanning %} have lower severities, the alerts are treated as warnings or notices and the check succeeds.
|
||||||
|
|
||||||
|
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.1" or currentVersion == "github-ae@next" %}You can override the default behavior in your repository settings, by specifying the level of severities that will cause a pull request check failure. For more information, see "[Defining the alert severities causing pull request check failure](/code-security/secure-coding/configuring-code-scanning#defining-the-alert-severities-causing-pull-request-check-failure)".
|
||||||
|
|
||||||
|
{% endif %}If your pull request targets a protected branch that uses {% data variables.product.prodname_code_scanning %}, and the repository owner has configured required status checks, then you must either fix or dismiss all error alerts before the pull request can be merged. For more information, see "[About protected branches](/github/administering-a-repository/about-protected-branches#require-status-checks-before-merging)."
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|||||||
@@ -298,7 +298,7 @@ Dependencies ignored by using the `@dependabot ignore` command are stored centra
|
|||||||
|
|
||||||
You can check whether a repository has stored `ignore` preferences by searching the repository for `"@dependabot ignore" in:comments`. If you wish to un-ignore a dependency ignored this way, re-open the pull request.
|
You can check whether a repository has stored `ignore` preferences by searching the repository for `"@dependabot ignore" in:comments`. If you wish to un-ignore a dependency ignored this way, re-open the pull request.
|
||||||
|
|
||||||
For more information about the `@dependabot ignore` commands, see "[Managing pull requests for dependency updates](/github/administering-a-repository/managing-pull-requests-for-dependency-updates)."
|
For more information about the `@dependabot ignore` commands, see "[Managing pull requests for dependency updates](/github/administering-a-repository/managing-pull-requests-for-dependency-updates#managing-dependabot-pull-requests-with-comment-commands)."
|
||||||
|
|
||||||
##### Specifying dependencies and versions to ignore
|
##### Specifying dependencies and versions to ignore
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,21 @@ By default, {% data variables.product.prodname_dependabot %} automatically rebas
|
|||||||
|
|
||||||
### Managing {% data variables.product.prodname_dependabot %} pull requests with comment commands
|
### Managing {% data variables.product.prodname_dependabot %} pull requests with comment commands
|
||||||
|
|
||||||
{% data variables.product.prodname_dependabot %} responds to simple commands in comments. Each pull request contains details of the commands you can use to process the pull request, for example: to merge, squash, reopen, close, or rebase the pull request. The aim is to make it as easy as possible for you to triage these automatically generated pull requests.
|
{% data variables.product.prodname_dependabot %} responds to simple commands in comments. Each pull request contains details of the commands you can use to process the pull request (for example: to merge, squash, reopen, close, or rebase the pull request) under the "{% data variables.product.prodname_dependabot %} commands and options" section. The aim is to make it as easy as possible for you to triage these automatically generated pull requests.
|
||||||
|
|
||||||
|
You can use any of the following commands on a {% data variables.product.prodname_dependabot %} pull request.
|
||||||
|
|
||||||
|
- `@dependabot cancel merge` cancels a previously requested merge.
|
||||||
|
- `@dependabot close` closes the pull request and prevents {% data variables.product.prodname_dependabot %} from recreating that pull request. You can achieve the same result by closing the pull request manually.
|
||||||
|
- `@dependabot ignore this dependency` closes the pull request and prevents {% data variables.product.prodname_dependabot %} from creating any more pull requests for this dependency (unless you reopen the pull request or upgrade to the suggested version of the dependency yourself).
|
||||||
|
- `@dependabot ignore this major version` closes the pull request and prevents {% data variables.product.prodname_dependabot %} from creating any more pull requests for this major version (unless you reopen the pull request or upgrade to this major version yourself).
|
||||||
|
- `@dependabot ignore this minor version` closes the pull request and prevents {% data variables.product.prodname_dependabot %} from creating any more pull requests for this minor version (unless you reopen the pull request or upgrade to this minor version yourself).
|
||||||
|
- `@dependabot merge` merges the pull request once your CI tests have passed.
|
||||||
|
- `@dependabot rebase` rebases the pull request.
|
||||||
|
- `@dependabot recreate` recreates the pull request, overwriting any edits that have been made to the pull request.
|
||||||
|
- `@dependabot reopen` reopens the pull request if the pull request is closed.
|
||||||
|
- `@dependabot squash and merge` squashes and merges the pull request once your CI tests have passed.
|
||||||
|
|
||||||
|
{% data variables.product.prodname_dependabot %} will react with a "thumbs up" emoji to acknowledge the command, and may respond with a comment on the pull request. While {% data variables.product.prodname_dependabot %} usually responds quickly, some commands may take several minutes to complete if {% data variables.product.prodname_dependabot %} is busy processing other updates or commands.
|
||||||
|
|
||||||
If you run any of the commands for ignoring dependencies or versions, {% data variables.product.prodname_dependabot %} stores the preferences for the repository centrally. While this is a quick solution, for repositories with more than one contributor it is better to explicitly define the dependencies and versions to ignore in the configuration file. This makes it easy for all contributors to see why a particular dependency isn't being updated automatically. For more information, see "[Configuration options for dependency updates](/github/administering-a-repository/configuration-options-for-dependency-updates#ignore)."
|
If you run any of the commands for ignoring dependencies or versions, {% data variables.product.prodname_dependabot %} stores the preferences for the repository centrally. While this is a quick solution, for repositories with more than one contributor it is better to explicitly define the dependencies and versions to ignore in the configuration file. This makes it easy for all contributors to see why a particular dependency isn't being updated automatically. For more information, see "[Configuration options for dependency updates](/github/administering-a-repository/configuration-options-for-dependency-updates#ignore)."
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ topics:
|
|||||||
|
|
||||||
{% if currentVersion == "free-pro-team@latest" %}
|
{% if currentVersion == "free-pro-team@latest" %}
|
||||||
|
|
||||||
You can store a variety of projects in {% data variables.product.product_name %} repositories, including open source projects. With [open source projects](http://opensource.org/about), you can share code to make better, more reliable software.
|
You can store a variety of projects in {% data variables.product.product_name %} repositories, including open source projects. With [open source projects](http://opensource.org/about), you can share code to make better, more reliable software. You can use repositories to collaborate with others and track your work. For more information, see "[About repositories](/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-repositories)."
|
||||||
|
|
||||||
{% elsif enterpriseServerVersions contains currentVersion or currentVersion == "github-ae@latest" %}
|
{% elsif enterpriseServerVersions contains currentVersion or currentVersion == "github-ae@latest" %}
|
||||||
|
|
||||||
@@ -82,6 +82,7 @@ Congratulations! You have now created a repository, including a *README* file, a
|
|||||||
|
|
||||||
- "[Set up Git](/articles/set-up-git)"
|
- "[Set up Git](/articles/set-up-git)"
|
||||||
- **Create a repository**
|
- **Create a repository**
|
||||||
|
- "[Clone a repository](/github/creating-cloning-and-archiving-repositories/cloning-a-repository)"
|
||||||
- "[Fork a repository](/articles/fork-a-repo)"
|
- "[Fork a repository](/articles/fork-a-repo)"
|
||||||
- "[Be social](/articles/be-social)"
|
- "[Be social](/articles/be-social)"
|
||||||
- {% data reusables.support.connect-in-the-forum-bootcamp %}
|
- {% data reusables.support.connect-in-the-forum-bootcamp %}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: Searching for information on GitHub
|
title: Searching for information on GitHub
|
||||||
|
intro: Use different types of searches to find the information you want.
|
||||||
redirect_from:
|
redirect_from:
|
||||||
- /categories/78/articles/
|
- /categories/78/articles/
|
||||||
- /categories/search/
|
- /categories/search/
|
||||||
@@ -14,4 +15,3 @@ children:
|
|||||||
- /getting-started-with-searching-on-github
|
- /getting-started-with-searching-on-github
|
||||||
- /searching-on-github
|
- /searching-on-github
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ For more information about adding people to your enterprise, see "{% if currentV
|
|||||||
|
|
||||||
Enterprise owners have complete control over the enterprise and can take every action, including:
|
Enterprise owners have complete control over the enterprise and can take every action, including:
|
||||||
- Managing administrators
|
- Managing administrators
|
||||||
- {% if currentVersion == "free-pro-team@latest" %}Adding and removing {% elsif currentVersion == "github-ae@latest" %}Managing{% endif %} organizations {% if currentVersion == "free-pro-team@latest" %}to and from {% elsif currentVersion == "github-ae@latest" %} in{% endif %} the enterprise
|
- {% if currentVersion == "free-pro-team@latest" %}Adding and removing {% elsif currentVersion == "github-ae@latest" or currentVersion ver_gt "enterprise-server@2.20" %}Managing{% endif %} organizations {% if currentVersion == "free-pro-team@latest" %}to and from {% elsif currentVersion == "github-ae@latest" or currentVersion ver_gt "enterprise-server@2.20" %} in{% endif %} the enterprise
|
||||||
- Managing enterprise settings
|
- Managing enterprise settings
|
||||||
- Enforcing policy across organizations
|
- Enforcing policy across organizations
|
||||||
{% if currentVersion == "free-pro-team@latest" %}- Managing billing settings{% endif %}
|
{% if currentVersion == "free-pro-team@latest" %}- Managing billing settings{% endif %}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ sections:
|
|||||||
changes:
|
changes:
|
||||||
- Check annotations older than 4 months will be archived.
|
- Check annotations older than 4 months will be archived.
|
||||||
known_issues:
|
known_issues:
|
||||||
|
- Access to a repository through the administrative shell using `ghe-repo <owner>/<reponame>` will hang. As a workaround, use `ghe-repo <owner>/<reponame> -c "bash -i"` until a fix is available in the next version.
|
||||||
- On a freshly set up GitHub Enterprise Server without any users, an attacker could create the first admin user.
|
- On a freshly set up GitHub Enterprise Server without any users, an attacker could create the first admin user.
|
||||||
- Custom firewall rules are not maintained during an upgrade.
|
- Custom firewall rules are not maintained during an upgrade.
|
||||||
- Git LFS tracked files [uploaded through the web interface](https://github.com/blog/2105-upload-files-to-your-repositories) are incorrectly added directly to the repository.
|
- Git LFS tracked files [uploaded through the web interface](https://github.com/blog/2105-upload-files-to-your-repositories) are incorrectly added directly to the repository.
|
||||||
|
|||||||
@@ -1,130 +1,20 @@
|
|||||||
date: '2021-05-06'
|
date: '2021-05-06'
|
||||||
release_candidate: true
|
release_candidate: true
|
||||||
|
deprecated: true
|
||||||
intro: If {% data variables.product.product_location %} is running a release candidate build, you can't upgrade with a hotpatch. We recommend only running release candidates on test environments.
|
intro: If {% data variables.product.product_location %} is running a release candidate build, you can't upgrade with a hotpatch. We recommend only running release candidates on test environments.
|
||||||
sections:
|
sections:
|
||||||
features:
|
security_fixes:
|
||||||
- heading: GitHub Advanced Security Secret Scanning
|
- '**MEDIUM** Under certain circumstances, users who were removed from a team or organization could retain write access to branches they had existing pull requests opened for.'
|
||||||
notes:
|
- Packages have been updated to the latest security versions.
|
||||||
- |
|
bugs:
|
||||||
[Secret Scanning](https://github.com/features/security) is now generally available on {% data variables.product.prodname_ghe_server %} 3.1+. Scan public and private repositories for committed credentials, find secrets, and notify the secret provider or admin the moment they are committed into a repository.
|
- 'A scheduled cleanup job can cause performance to degrade on an instance with a very large `check_annotations` table.'
|
||||||
|
|
||||||
This release includes several improvements from the beta of Secret Scanning on {% data variables.product.prodname_ghe_server %}:
|
|
||||||
|
|
||||||
- Expanded our [pattern coverage](/enterprise-server@3.1/code-security/secret-security/about-secret-scanning#about-secret-scanning-for-private-repositories) from 24 partners to 37
|
|
||||||
- Added an [API](/rest/reference/secret-scanning) and [webhooks](/developers/webhooks-and-events/webhook-events-and-payloads#secret_scanning_alert)
|
|
||||||
- Added [notifications for commit authors](https://github.blog/changelog/2021-03-05-secret-scanning-notifications-for-commit-authors-on-private-repositories/) when they commit secrets
|
|
||||||
- Updated the index view to made it easy to triage secrets in bulk
|
|
||||||
- Reduced the false positive rate on many patterns
|
|
||||||
|
|
||||||
Administrators using {% data variables.product.prodname_GH_advanced_security %} can [enable and configure](/enterprise-server@3.1/admin/configuration/configuring-secret-scanning-for-your-appliance) {% data variables.product.prodname_GH_advanced_security %} secret scanning. You can review the [updated minimum requirements for your platform](/enterprise-server@3.1/admin/installation/setting-up-a-github-enterprise-server-instance) before you turn on {% data variables.product.prodname_GH_advanced_security %} secret scanning.
|
|
||||||
|
|
||||||
- heading: GitHub Advanced Security Code Scanning
|
|
||||||
notes:
|
|
||||||
- |
|
|
||||||
[{% data variables.product.prodname_GH_advanced_security %} code scanning](https://github.com/features/security) is now generally available on {% data variables.product.prodname_ghe_server %} 3.1+. Organizations who have purchased {% data variables.product.prodname_GH_advanced_security %} can use this capability to do static analysis security testing against their code, and prevent vulnerabilities from making it to their production code using CodeQL, our semantic analysis engine. For more information, see "[Configuring code scanning on your appliance](/en/enterprise-server@3.1/admin/configuration/configuring-code-scanning-for-your-appliance#running-code-scanning-using-github-actions)."
|
|
||||||
|
|
||||||
- heading: GitHub Advanced Security billing improvements
|
|
||||||
notes:
|
|
||||||
- |
|
|
||||||
This release includes several improvements to {% data variables.product.prodname_GH_advanced_security %} billing in {% data variables.product.prodname_ghe_server %}:
|
|
||||||
|
|
||||||
- {% data variables.product.prodname_GH_advanced_security %} customers can now view their active committer count and the remaining number of unused committer seats on their organization or enterprise account’s Billing page. If Advanced Security is purchased for an enterprise, administrators can also view the active committer seats which are being used by other organizations within their enterprise. For more information, see "[About GitHub Advanced Security licensing](/enterprise-server@3.1/admin/advanced-security/about-licensing-for-github-advanced-security)" and "[Viewing your GitHub Advanced Security usage](/enterprise-server@3.1/admin/advanced-security/viewing-your-github-advanced-security-usage)."
|
|
||||||
- GitHub Advanced Security customers can now view their active committer count for any Advanced Security enabled repositories on their organization or enterprise account's Billing page. These changes help billing administrators track their usage against how many committer licenses they purchased. For more information see "[Managing security and analysis settings for your organization](/enterprise-server@3.1/organizations/keeping-your-organization-secure/managing-security-and-analysis-settings-for-your-organization)."
|
|
||||||
|
|
||||||
- heading: Dependabot improvements
|
|
||||||
notes:
|
|
||||||
- |
|
|
||||||
This release includes improvements to Dependabot alerts in {% data variables.product.prodname_ghe_server %}:
|
|
||||||
|
|
||||||
- Users with Dependabot alerts enabled can see which of their repositories are impacted by a given vulnerability by navigating to its entry in the [GitHub Advisory Database](https://github.com/advisories). This feature is available in public beta. For more information, see "[Viewing and updating vulnerable dependencies in your repository](/enterprise-server@3.1/code-security/supply-chain-security/viewing-and-updating-vulnerable-dependencies-in-your-repository)."
|
|
||||||
- When a vulnerability is added to GitHub Advisory Database, you will no longer receive [email and web notifications](https://github.com/notifications) for Dependabot alerts on low and moderate severity vulnerabilities. These alerts are still accessible from the repository's Security tab. For more information, see [Viewing and updating vulnerable dependencies in your repository](/enterprise-server@3.1/code-security/supply-chain-security/viewing-and-updating-vulnerable-dependencies-in-your-repository).
|
|
||||||
- 'You can now give people instructions on how to responsibly report security vulnerabilities in your project by adding a `SECURITY.md` file to your repository's `root`, `docs`, or `.github` folder. When someone creates an issue in your repository, they will see a link to your project's security policy. For more information, see "[Adding a security policy to your repository](/enterprise-server@3.1/code-security/getting-started/adding-a-security-policy-to-your-repository)."'
|
|
||||||
|
|
||||||
- heading: GitHub Actions Workflow Visualization beta
|
|
||||||
notes:
|
|
||||||
- |
|
|
||||||
|
|
||||||
GitHub Actions can now generate a visual graph of your workflow on every run. With workflow visualization, you can:
|
|
||||||
- View and understand complex workflows
|
|
||||||
- Track progress of workflows in real-time
|
|
||||||
- Troubleshoot runs quickly by easily accessing logs and jobs metadata
|
|
||||||
- Monitor progress of deployment jobs and easily access deployment targets
|
|
||||||
|
|
||||||
For more information, see "[Using the visualization graph](/actions/managing-workflow-runs/using-the-visualization-graph)."
|
|
||||||
|
|
||||||
- heading: OAuth 2.0 Device Authorization Grant
|
|
||||||
notes:
|
|
||||||
- |
|
|
||||||
[OAuth 2.0 Device Authorization Grant](https://github.com/login/device) allows any CLI client or developer tool to authenticate using a secondary system with a browser.
|
|
||||||
|
|
||||||
Administrators using [OAuth Apps](/developers/apps/authorizing-oauth-apps#device-flow) and [GitHub Apps](/developers/apps/authorizing-oauth-apps#device-flow) can [enable and configure](/enterprise-server@3.1/admin/configuration/configuring-secret-scanning-for-your-appliance) OAuth 2.0 Device Authorization Flow, in addition to the existing Web Application Flow. You can review the [updated minimum requirements for your platform](/enterprise-server@3.1/admin/installation/setting-up-a-github-enterprise-server-instance) before you enable OAuth 2.0 Device Authorization Flow.
|
|
||||||
|
|
||||||
- heading: Pull request auto-merge
|
|
||||||
notes:
|
|
||||||
- |
|
|
||||||
With auto-merge, pull requests can be set to merge automatically when all merge requirements have been satisfied. This saves users from needing to constantly check the state of their pull requests just to merge them. Auto-merge can be enabled by a user with permission to merge and on pull requests that have unsatisfied merge requirements. For more information, see "[Automatically merging a pull request](/enterprise-server@3.1/github/collaborating-with-issues-and-pull-requests/automatically-merging-a-pull-request)."
|
|
||||||
|
|
||||||
- heading: Custom notifications
|
|
||||||
notes:
|
|
||||||
- |
|
|
||||||
You can customize the types of notifications you want to receive from individual repositories. For more information, see "[Configuring notifications](/enterprise-server@3.1/github/managing-subscriptions-and-notifications-on-github/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository)."
|
|
||||||
|
|
||||||
changes:
|
changes:
|
||||||
- heading: Administration Changes
|
- Check annotations older than 4 months will be archived.
|
||||||
notes:
|
- 'The `firstPatchedVersion` field is now available on `SecurityVulnerability` objects in the GraphQL API.'
|
||||||
- By precomputing checksums, the amount of time a repository is under the lock has reduced dramatically, allowing more write operations to succeed immediately and improving monorepo performance.
|
|
||||||
- The latest release of the CodeQL CLI supports uploading analysis results to GitHub. This makes it easier to run code analysis for customers who wish to use CI/CD systems other than GitHub Actions. Previously, such users had to use the separate CodeQL runner, which will continue to be available. For more information, see "[About CodeQL code scanning in your CI system](/enterprise-server@3.1/code-security/secure-coding/about-codeql-code-scanning-in-your-ci-system)."
|
|
||||||
- GitHub Actions now supports skipping `push` and `pull_request` workflows by looking for some common keywords in your commit message.
|
|
||||||
- Check annotations older than four months will be archived.
|
|
||||||
|
|
||||||
- heading: Security Changes
|
|
||||||
notes:
|
|
||||||
- Display of Code Scanning results on a pull request without submitting with a pull request ID is no longer supported. For more information, see "[Configuring code scanning](/enterprise-server@3.1/code-security/secure-coding/configuring-code-scanning#scanning-pull-requests)" and "[Configuring CodeQL code scanning in your CI system](/enterprise-server@3.1/code-security/secure-coding/configuring-codeql-code-scanning-in-your-ci-system#scanning-pull-requests).
|
|
||||||
- SARIF upload support increased to a maximum of 5000 results per upload.
|
|
||||||
|
|
||||||
- heading: Developer Changes
|
|
||||||
notes:
|
|
||||||
- You can specify multiple callback URLs while configuring a GitHub App. This can be used in services with multiple domains or subdomains. GitHub will always deny authorization if the callback URL from the request is not in the authorization callback URL list.
|
|
||||||
- The GitHub App file permission has been updated to allow an app developer to specify up to 10 files for read-only or read-write access that their app can request access to.
|
|
||||||
- CodeQL now supports more [libraries and frameworks](https://codeql.github.com/docs/codeql-overview/supported-languages-and-frameworks/) for a variety of languages ([C++](https://github.com/github/codeql/tree/main/cpp), [JavaScript](https://github.com/github/codeql/tree/main/javascript), [Python](https://github.com/github/codeql/tree/main/python),[Java](https://github.com/github/codeql/tree/main/java), [Go](https://github.com/github/codeql-go/tree/main)). The CodeQL engine can now detect more sources of untrusted user data, which improves the quality and depth of the code scanning alerts. For more information, see "[About CodeQL](https://codeql.github.com/docs/codeql-overview/about-codeql/)."
|
|
||||||
- When configuring a GitHub App, the authorization callback URL is a required field. Now, we allow the developer to specify multiple callback URLs. This can be used in services with multiple domains or subdomains. GitHub will always deny authorization if the callback URL from the request is not in the authorization callback URL list.
|
|
||||||
- Delete an entire directory of files, including subdirectories, from your web browser. For more information, see "[Deleting a file or directory](/enterprise-server@3.1/github/managing-files-in-a-repository/deleting-files-in-a-repository#deleting-a-directory)."
|
|
||||||
- 'Include multiple words after the `#` in an issue, discussion, or pull request comment to further narrow your search.'
|
|
||||||
- 'When you’re writing an issue, pull request, or discussion comment the list syntax for bullets, numbers, and tasks autocompletes after you press `return` or `enter`.'
|
|
||||||
|
|
||||||
- heading: API Changes
|
|
||||||
notes:
|
|
||||||
- The code scanning API allows users to upload data about static analysis security testing results, or export data about alerts. For more information, see the [code scanning API reference](https://docs.github.com/en/rest/reference/code-scanning).
|
|
||||||
- The [GitHub Apps API](https://docs.github.com/rest/reference/apps) for managing installations has now graduated from an API preview to a generally available API. The [preview header](https://docs.github.com/rest/overview/api-previews) is no longer required to access these endpoints.
|
|
||||||
|
|
||||||
known_issues:
|
known_issues:
|
||||||
- The GitHub Packages 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.
|
- The GitHub Packages 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.
|
||||||
- 'A scheduled cleanup job can cause performance to degrade on an instance with a very large `check_annotations` table.'
|
|
||||||
- On a freshly set up GitHub Enterprise Server without any users, an attacker could create the first admin user.
|
- On a freshly set up GitHub Enterprise Server without any users, an attacker could create the first admin user.
|
||||||
- Custom firewall rules are not maintained during an upgrade.
|
- Custom firewall rules are not maintained during an upgrade.
|
||||||
- Git LFS tracked files [uploaded through the web interface](https://github.com/blog/2105-upload-files-to-your-repositories) are incorrectly added directly to the repository.
|
- Git LFS tracked files [uploaded through the web interface](https://github.com/blog/2105-upload-files-to-your-repositories) are incorrectly added directly to the repository.
|
||||||
- Issues cannot be closed if they contain a permalink to a blob in the same repository where the file path is longer than 255 characters.
|
- Issues cannot be closed if they contain a permalink to a blob in the same repository where the file path is longer than 255 characters.
|
||||||
- When "Users can search GitHub.com" is enabled with GitHub Connect, issues in private and internal repositories are not included in GitHub.com search results.
|
- When "Users can search GitHub.com" is enabled with GitHub Connect, issues in private and internal repositories are not included in GitHub.com search results.
|
||||||
|
|
||||||
deprecations:
|
|
||||||
- heading: Deprecation of GitHub Enterprise Server 2.20
|
|
||||||
notes:
|
|
||||||
- '**{% data variables.product.prodname_ghe_server %} 2.20 was discontinued on March 2, 2021**. That means that no patch releases will be made, even for critical security issues, after this date. For better performance, improved security, and new features, [upgrade to the newest version of {% data variables.product.prodname_ghe_server %}](/enterprise-server@3.1/admin/enterprise-management/upgrading-github-enterprise-server) as soon as possible.'
|
|
||||||
- heading: Deprecation of GitHub Enterprise Server 2.21
|
|
||||||
notes:
|
|
||||||
- '**{% data variables.product.prodname_ghe_server %} 2.21 will be discontinued on June 9, 2021**. That means that no patch releases will be made, even for critical security issues, after this date. For better performance, improved security, and new features, [upgrade to the newest version of {% data variables.product.prodname_ghe_server %}](/enterprise-server@3.1/admin/enterprise-management/upgrading-github-enterprise-server) as soon as possible.'
|
|
||||||
- heading: Deprecation of Legacy GitHub App Webhook Events
|
|
||||||
notes:
|
|
||||||
- 'Starting with {% data variables.product.prodname_ghe_server %} 2.21.0 two legacy GitHub Apps-related webhook events have been deprecated and will be removed in {% data variables.product.prodname_ghe_server %} 3.2.0. The deprecated events `integration_installation` and `integration_installation_repositories` have equivalent events which will be supported. More information is available in the [deprecation announcement blog post](https://developer.github.com/changes/2020-04-15-replacing-the-installation-and-installation-repositories-events/).'
|
|
||||||
- heading: Deprecation of Legacy GitHub Apps Endpoint
|
|
||||||
notes:
|
|
||||||
- Starting with {% data variables.product.prodname_ghe_server %} 2.21.0 the legacy GitHub Apps endpoint for creating installation access tokens was deprecated and will be removed in {% data variables.product.prodname_ghe_server %} 3.2.0. More information is available in the [deprecation announcement blog post](https://developer.github.com/changes/2020-04-15-replacing-create-installation-access-token-endpoint/).
|
|
||||||
- heading: Deprecation of OAuth Application API
|
|
||||||
notes:
|
|
||||||
- 'GitHub no longer supports the OAuth application endpoints that contain `access_token` as a path parameter. We have introduced new endpoints that allow you to securely manage tokens for OAuth Apps by moving `access_token` to the request body. While deprecated, the endpoints are still accessible in this version. We intend to remove these endpoints on {% data variables.product.prodname_ghe_server %} 3.4. For more information, see the [deprecation announcement blog post](https://developer.github.com/changes/2020-02-14-deprecating-oauth-app-endpoint/).'
|
|
||||||
- heading: Deprecation of GitHub Actions short SHA support
|
|
||||||
notes:
|
|
||||||
- GitHub Actions will remove support for referencing actions using the shortened version of a git commit SHA. This may cause some workflows in your repository to break. To fix these workflows, you will need to update the action reference to use the full commit SHA. For more information, see "[Security hardening for GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/security-hardening-for-github-actions#using-third-party-actions)."
|
|
||||||
|
|
||||||
backups:
|
|
||||||
- '{% data variables.product.prodname_ghe_server %} 3.1 requires at least [GitHub Enterprise Backup Utilities 3.1.0](https://github.com/github/backup-utils) for [Backups and Disaster Recovery](/enterprise-server@3.1/admin/configuration/configuring-backups-on-your-appliance).'
|
|
||||||
|
|||||||
159
data/release-notes/enterprise-server/3-1/0.yml
Normal file
159
data/release-notes/enterprise-server/3-1/0.yml
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
date: '2021-06-03'
|
||||||
|
intro: For minimum infrastructure requirements, see "[About minimum requirements for {% data variables.product.prodname_ghe_server %} 3.0 and later](/admin/enterprise-management/upgrading-github-enterprise-server#about-minimum-requirements-for-github-enterprise-server-30-and-later)."
|
||||||
|
sections:
|
||||||
|
features:
|
||||||
|
- heading: GitHub Advanced Security Secret Scanning
|
||||||
|
notes:
|
||||||
|
- |
|
||||||
|
[Secret Scanning](https://github.com/features/security) is now generally available on {% data variables.product.prodname_ghe_server %} 3.1+. Scan public and private repositories for committed credentials, find secrets, and notify the secret provider or admin the moment they are committed into a repository.
|
||||||
|
|
||||||
|
This release includes several improvements from the beta of Secret Scanning on {% data variables.product.prodname_ghe_server %}:
|
||||||
|
|
||||||
|
- Expanded our [pattern coverage](/enterprise-server@3.1/code-security/secret-security/about-secret-scanning#about-secret-scanning-for-private-repositories) from 24 partners to 37
|
||||||
|
- Added an [API](/rest/reference/secret-scanning) and [webhooks](/developers/webhooks-and-events/webhook-events-and-payloads#secret_scanning_alert)
|
||||||
|
- Added [notifications for commit authors](https://github.blog/changelog/2021-03-05-secret-scanning-notifications-for-commit-authors-on-private-repositories/) when they commit secrets
|
||||||
|
- Updated the index view to made it easy to triage secrets in bulk
|
||||||
|
- Reduced the false positive rate on many patterns
|
||||||
|
|
||||||
|
Administrators using {% data variables.product.prodname_GH_advanced_security %} can [enable and configure](/enterprise-server@3.1/admin/configuration/configuring-secret-scanning-for-your-appliance) {% data variables.product.prodname_GH_advanced_security %} secret scanning. You can review the [updated minimum requirements for your platform](/enterprise-server@3.1/admin/installation/setting-up-a-github-enterprise-server-instance) before you turn on {% data variables.product.prodname_GH_advanced_security %} secret scanning.
|
||||||
|
|
||||||
|
- heading: GitHub Advanced Security billing improvements
|
||||||
|
notes:
|
||||||
|
- |
|
||||||
|
This release includes several improvements to {% data variables.product.prodname_GH_advanced_security %} billing in {% data variables.product.prodname_ghe_server %}:
|
||||||
|
|
||||||
|
- {% data variables.product.prodname_GH_advanced_security %} customers can now view their active committer count and the remaining number of unused committer seats on their organization or enterprise account’s Billing page. If Advanced Security is purchased for an enterprise, administrators can also view the active committer seats which are being used by other organizations within their enterprise. For more information, see "[About GitHub Advanced Security licensing](/enterprise-server@3.1/admin/advanced-security/about-licensing-for-github-advanced-security)" and "[Viewing your GitHub Advanced Security usage](/enterprise-server@3.1/admin/advanced-security/viewing-your-github-advanced-security-usage)."
|
||||||
|
- GitHub Advanced Security customers can now view their active committer count for any Advanced Security enabled repositories on their organization or enterprise account's Billing page. These changes help billing administrators track their usage against how many committer licenses they purchased. For more information see "[Managing security and analysis settings for your organization](/enterprise-server@3.1/organizations/keeping-your-organization-secure/managing-security-and-analysis-settings-for-your-organization)."
|
||||||
|
|
||||||
|
- heading: Dependabot improvements
|
||||||
|
notes:
|
||||||
|
- |
|
||||||
|
This release includes improvements to Dependabot alerts in {% data variables.product.prodname_ghe_server %}:
|
||||||
|
|
||||||
|
- Users with Dependabot alerts enabled can see which of their repositories are impacted by a given vulnerability by navigating to its entry in the [GitHub Advisory Database](https://github.com/advisories). This feature is available in public beta. For more information, see "[Viewing and updating vulnerable dependencies in your repository](/enterprise-server@3.1/code-security/supply-chain-security/viewing-and-updating-vulnerable-dependencies-in-your-repository)."
|
||||||
|
- When a vulnerability is added to GitHub Advisory Database, you will no longer receive [email and web notifications](https://github.com/notifications) for Dependabot alerts on low and moderate severity vulnerabilities. These alerts are still accessible from the repository's Security tab. For more information, see "[Viewing and updating vulnerable dependencies in your repository](/enterprise-server@3.1/code-security/supply-chain-security/viewing-and-updating-vulnerable-dependencies-in-your-repository)."
|
||||||
|
- You can now give people instructions on how to responsibly report security vulnerabilities in your project by adding a `SECURITY.md` file to your repository's `root`, `docs`, or `.github` folder. When someone creates an issue in your repository, they will see a link to your project's security policy. For more information, see "[Adding a security policy to your repository](/enterprise-server@3.1/code-security/getting-started/adding-a-security-policy-to-your-repository)."
|
||||||
|
|
||||||
|
- heading: GitHub Actions Workflow Visualization beta
|
||||||
|
notes:
|
||||||
|
- |
|
||||||
|
{% data variables.product.prodname_actions %} can now generate a visual graph of your workflow on every run. With workflow visualization, you can:
|
||||||
|
- View and understand complex workflows
|
||||||
|
- Track progress of workflows in real-time
|
||||||
|
- Troubleshoot runs quickly by easily accessing logs and jobs metadata
|
||||||
|
- Monitor progress of deployment jobs and easily access deployment targets
|
||||||
|
|
||||||
|
For more information, see "[Using the visualization graph](/actions/managing-workflow-runs/using-the-visualization-graph)."
|
||||||
|
|
||||||
|
- heading: OAuth 2.0 Device Authorization Grant
|
||||||
|
notes:
|
||||||
|
- |
|
||||||
|
[OAuth 2.0 Device Authorization Grant](https://github.com/login/device) allows any CLI client or developer tool to authenticate using a secondary system with a browser.
|
||||||
|
|
||||||
|
Administrators using [OAuth Apps](/developers/apps/authorizing-oauth-apps#device-flow) and [GitHub Apps](/developers/apps/authorizing-oauth-apps#device-flow) can enable and configure OAuth 2.0 Device Authorization Flow, in addition to the existing Web Application Flow. You can review the [updated minimum requirements for your platform](/enterprise-server@3.1/admin/installation/setting-up-a-github-enterprise-server-instance) before you enable OAuth 2.0 Device Authorization Flow.
|
||||||
|
|
||||||
|
- heading: Pull request auto-merge
|
||||||
|
notes:
|
||||||
|
- |
|
||||||
|
With auto-merge, pull requests can be set to merge automatically when all merge requirements have been satisfied. This saves users from needing to constantly check the state of their pull requests just to merge them. Auto-merge can be enabled by a user with permission to merge and on pull requests that have unsatisfied merge requirements. For more information, see "[Automatically merging a pull request](/enterprise-server@3.1/github/collaborating-with-issues-and-pull-requests/automatically-merging-a-pull-request)."
|
||||||
|
|
||||||
|
- heading: Custom notifications
|
||||||
|
notes:
|
||||||
|
- |
|
||||||
|
You can customize the types of notifications you want to receive from individual repositories. For more information, see "[Configuring notifications](/enterprise-server@3.1/github/managing-subscriptions-and-notifications-on-github/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository)."
|
||||||
|
|
||||||
|
- heading: GitHub Mobile filtering
|
||||||
|
notes:
|
||||||
|
- |
|
||||||
|
[{% data variables.product.prodname_mobile %}](https://github.com/mobile) filtering allows you to search for and find issues, pull requests, and discussions from your device. New metadata for issues and pull request list items allow you to filter by assignees, checks status, review states, and comment counts.
|
||||||
|
|
||||||
|
{% data variables.product.prodname_mobile %} beta is available for {% data variables.product.prodname_ghe_server %}. Sign in with our [Android](https://play.google.com/store/apps/details?id=com.github.android) and [iOS](https://apps.apple.com/app/github/id1477376905) apps to triage notifications and manage issues and pull requests on the go. Administrators can disable mobile support for their Enterprise using the management console or by running `ghe-config app.mobile.enabled false`. For more information, see "[GitHub for mobile](/github/getting-started-with-github/using-github/github-for-mobile)."
|
||||||
|
|
||||||
|
changes:
|
||||||
|
- heading: Administration Changes
|
||||||
|
notes:
|
||||||
|
- By precomputing checksums, the amount of time a repository is under the lock has reduced dramatically, allowing more write operations to succeed immediately and improving monorepo performance.
|
||||||
|
- The latest release of the CodeQL CLI supports uploading analysis results to GitHub. This makes it easier to run code analysis for customers who wish to use CI/CD systems other than {% data variables.product.prodname_actions %}. Previously, such users had to use the separate CodeQL runner, which will continue to be available. For more information, see "[About CodeQL code scanning in your CI system](/enterprise-server@3.1/code-security/secure-coding/about-codeql-code-scanning-in-your-ci-system)."
|
||||||
|
- '{% data variables.product.prodname_actions %} now supports skipping `push` and `pull_request` workflows by looking for some common keywords in your commit message.'
|
||||||
|
- Check annotations older than four months will be archived.
|
||||||
|
|
||||||
|
- heading: Security Changes
|
||||||
|
notes:
|
||||||
|
- Following feedback, display of Code Scanning results on a pull request without submitting with a pull request ID will remain supported. For more information, see "[Configuring code scanning](/enterprise-server@3.1/code-security/secure-coding/configuring-code-scanning#scanning-pull-requests)" and "[Configuring CodeQL code scanning in your CI system](/enterprise-server@3.1/code-security/secure-coding/configuring-codeql-code-scanning-in-your-ci-system#scanning-pull-requests).
|
||||||
|
- SARIF upload support increased to a maximum of 5000 results per upload.
|
||||||
|
|
||||||
|
- heading: Developer Changes
|
||||||
|
notes:
|
||||||
|
- You can specify multiple callback URLs while configuring a GitHub App. This can be used in services with multiple domains or subdomains. GitHub will always deny authorization if the callback URL from the request is not in the authorization callback URL list.
|
||||||
|
- The GitHub App file permission has been updated to allow an app developer to specify up to 10 files for read-only or read-write access that their app can request access to.
|
||||||
|
- CodeQL now supports more [libraries and frameworks](https://codeql.github.com/docs/codeql-overview/supported-languages-and-frameworks/) for a variety of languages ([C++](https://github.com/github/codeql/tree/main/cpp), [JavaScript](https://github.com/github/codeql/tree/main/javascript), [Python](https://github.com/github/codeql/tree/main/python),[Java](https://github.com/github/codeql/tree/main/java), [Go](https://github.com/github/codeql-go/tree/main)). The CodeQL engine can now detect more sources of untrusted user data, which improves the quality and depth of the code scanning alerts. For more information, see "[About CodeQL](https://codeql.github.com/docs/codeql-overview/about-codeql/)."
|
||||||
|
- When configuring a GitHub App, the authorization callback URL is a required field. Now, we allow the developer to specify multiple callback URLs. This can be used in services with multiple domains or subdomains. GitHub will always deny authorization if the callback URL from the request is not in the authorization callback URL list.
|
||||||
|
- Delete an entire directory of files, including subdirectories, from your web browser. For more information, see "[Deleting a file or directory](/enterprise-server@3.1/github/managing-files-in-a-repository/deleting-files-in-a-repository#deleting-a-directory)."
|
||||||
|
- 'Include multiple words after the `#` in an issue, discussion, or pull request comment to further narrow your search.'
|
||||||
|
- 'When you’re writing an issue, pull request, or discussion comment the list syntax for bullets, numbers, and tasks autocompletes after you press `return` or `enter`.'
|
||||||
|
|
||||||
|
- heading: API Changes
|
||||||
|
notes:
|
||||||
|
- The code scanning API allows users to upload data about static analysis security testing results, or export data about alerts. For more information, see the [code scanning API reference](/rest/reference/code-scanning).
|
||||||
|
- The [GitHub Apps API](/rest/reference/apps) for managing installations has now graduated from an API preview to a generally available API. The [preview header](/rest/overview/api-previews) is no longer required to access these endpoints.
|
||||||
|
|
||||||
|
security_fixes:
|
||||||
|
- '**MEDIUM** Under certain circumstances, users who were removed from a team or organization could retain write access to branches they had existing pull requests opened for.'
|
||||||
|
- Packages have been updated to the latest security versions.
|
||||||
|
|
||||||
|
bugs:
|
||||||
|
- heading: Fixes for known issues from Release Candidate
|
||||||
|
notes:
|
||||||
|
- All known issues from Release Candidate 1 have been fixed, except those listed in the Known Issues section below.
|
||||||
|
- heading: Fixes for other issues
|
||||||
|
notes:
|
||||||
|
- On the "Configure Actions and Packages" page of the initial installation process, clicking on the "Test domain settings" button did not complete the test.
|
||||||
|
- 'Running `ghe-btop` failed with an error and cannot find a `babeld` container.'
|
||||||
|
- MySQL could reload and cause downtime if you change auto failover settings.
|
||||||
|
- After upgrading, a mismatch of internal and external timeout values created service unavailability.
|
||||||
|
- Expected replication delays in MSSQL generated warnings.
|
||||||
|
- 'Link to "[Configuring clustering](/admin/enterprise-management/configuring-clustering)" on the Management Console was incorrect.'
|
||||||
|
- When creating or editing a pre-receive hook, a race condition in the user interface meant that after selecting a repository, files within the repository were sometimes not populated in files dropdown.
|
||||||
|
- When an IP address is added to a whitelist using "Create Whitelist Entry" button, it could still be shown as locked out.
|
||||||
|
- References to the "Dependency graph" and "Dependabot alerts" features were not shown as disabled on some repositories.
|
||||||
|
- Setting an announcement in the enterprise account settings could result in a 500 Internal Server Error.
|
||||||
|
- HTTP POST requests to the `/hooks` endpoint could fail with a 401 response due to an incorrectly configured `hookID`.
|
||||||
|
- The `build-server` process failed to clean up processes, leaving them in the `defunct` state.
|
||||||
|
- '`spokesd` created excessive log entries, including the phrase "fixing placement skipped".'
|
||||||
|
- While upgrading Actions the upgrade could fail if the instance could not make self-requests via its configured hostname.
|
||||||
|
- Upgrading from 2.22.x to 3.1.0.rc1 could result in a database migration error relating to the `BackfillIntegrationApplicationCallbackUrlsTransition` data transition.
|
||||||
|
|
||||||
|
known_issues:
|
||||||
|
- Access to a repository through the administrative shell using `ghe-repo <owner>/<reponame>` will hang. As a workaround, use `ghe-repo <owner>/<reponame> -c "bash -i"` until a fix is available in the next version.
|
||||||
|
- 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.
|
||||||
|
- Custom firewall rules are not maintained during an upgrade.
|
||||||
|
- Git LFS tracked files [uploaded through the web interface](https://github.com/blog/2105-upload-files-to-your-repositories) are incorrectly added directly to the repository.
|
||||||
|
- Issues cannot be closed if they contain a permalink to a blob in the same repository where the file path is longer than 255 characters.
|
||||||
|
- When "Users can search GitHub.com" is enabled with GitHub Connect, issues in private and internal repositories are not included in GitHub.com search results.
|
||||||
|
|
||||||
|
deprecations:
|
||||||
|
- heading: Deprecation of GitHub Enterprise Server 2.20
|
||||||
|
notes:
|
||||||
|
- '**{% data variables.product.prodname_ghe_server %} 2.20 was discontinued on March 2, 2021**. That means that no patch releases will be made, even for critical security issues, after this date. For better performance, improved security, and new features, [upgrade to the newest version of {% data variables.product.prodname_ghe_server %}](/enterprise-server@3.1/admin/enterprise-management/upgrading-github-enterprise-server) as soon as possible.'
|
||||||
|
- heading: Deprecation of GitHub Enterprise Server 2.21
|
||||||
|
notes:
|
||||||
|
- '**{% data variables.product.prodname_ghe_server %} 2.21 will be discontinued on June 9, 2021**. That means that no patch releases will be made, even for critical security issues, after this date. For better performance, improved security, and new features, [upgrade to the newest version of {% data variables.product.prodname_ghe_server %}](/enterprise-server@3.1/admin/enterprise-management/upgrading-github-enterprise-server) as soon as possible.'
|
||||||
|
- heading: Deprecation of Legacy GitHub App Webhook Events
|
||||||
|
notes:
|
||||||
|
- 'Starting with {% data variables.product.prodname_ghe_server %} 2.21.0 two legacy GitHub Apps-related webhook events have been deprecated and will be removed in {% data variables.product.prodname_ghe_server %} 3.2.0. The deprecated events `integration_installation` and `integration_installation_repositories` have equivalent events which will be supported. More information is available in the [deprecation announcement blog post](https://developer.github.com/changes/2020-04-15-replacing-the-installation-and-installation-repositories-events/).'
|
||||||
|
- heading: Deprecation of Legacy GitHub Apps Endpoint
|
||||||
|
notes:
|
||||||
|
- Starting with {% data variables.product.prodname_ghe_server %} 2.21.0 the legacy GitHub Apps endpoint for creating installation access tokens was deprecated and will be removed in {% data variables.product.prodname_ghe_server %} 3.2.0. More information is available in the [deprecation announcement blog post](https://developer.github.com/changes/2020-04-15-replacing-create-installation-access-token-endpoint/).
|
||||||
|
- heading: Deprecation of OAuth Application API
|
||||||
|
notes:
|
||||||
|
- 'GitHub no longer supports the OAuth application endpoints that contain `access_token` as a path parameter. We have introduced new endpoints that allow you to securely manage tokens for OAuth Apps by moving `access_token` to the request body. While deprecated, the endpoints are still accessible in this version. We intend to remove these endpoints on {% data variables.product.prodname_ghe_server %} 3.4. For more information, see the [deprecation announcement blog post](https://developer.github.com/changes/2020-02-14-deprecating-oauth-app-endpoint/).'
|
||||||
|
- heading: Deprecation of GitHub Actions short SHA support
|
||||||
|
notes:
|
||||||
|
- '{% data variables.product.prodname_actions %} will remove support for referencing actions using the shortened version of a git commit SHA. This may cause some workflows in your repository to break. To fix these workflows, you will need to update the action reference to use the full commit SHA. For more information, see "[Security hardening for {% data variables.product.prodname_actions %}](/actions/learn-github-actions/security-hardening-for-github-actions#using-third-party-actions)."'
|
||||||
|
- heading: Deprecation of XenServer Hypervisor support
|
||||||
|
notes:
|
||||||
|
- Beginning in {% data variables.product.prodname_ghe_server %} 3.1, we will begin discontinuing support for Xen Hypervisor. The complete deprecation is scheduled for {% data variables.product.prodname_ghe_server %} 3.3, following the standard one year deprecation window.
|
||||||
|
|
||||||
|
backups:
|
||||||
|
- '{% data variables.product.prodname_ghe_server %} 3.1 requires at least [GitHub Enterprise Backup Utilities 3.1.0](https://github.com/github/backup-utils) for [Backups and Disaster Recovery](/enterprise-server@3.1/admin/configuration/configuring-backups-on-your-appliance).'
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
1. From the list of GPG keys, copy the GPG key ID you'd like to use. In this example, the GPG key ID is `3AA5C34371567BD2`:
|
1. From the list of GPG keys, copy the long form of the GPG key ID you'd like to use. In this example, the GPG key ID is `3AA5C34371567BD2`:
|
||||||
```shell
|
```shell
|
||||||
$ gpg --list-secret-keys --keyid-format LONG
|
$ gpg --list-secret-keys --keyid-format=long
|
||||||
/Users/hubot/.gnupg/secring.gpg
|
/Users/hubot/.gnupg/secring.gpg
|
||||||
------------------------------------
|
------------------------------------
|
||||||
sec 4096R/<em>3AA5C34371567BD2</em> 2016-03-10 [expires: 2017-03-10]
|
sec 4096R/<em>3AA5C34371567BD2</em> 2016-03-10 [expires: 2017-03-10]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
1. Use the `gpg --list-secret-keys --keyid-format LONG` command to list GPG keys for which you have both a public and private key. A private key is required for signing commits or tags.
|
1. Use the `gpg --list-secret-keys --keyid-format=long` command to list the long form of the GPG keys for which you have both a public and private key. A private key is required for signing commits or tags.
|
||||||
```shell
|
```shell
|
||||||
$ gpg --list-secret-keys --keyid-format LONG
|
$ gpg --list-secret-keys --keyid-format=long
|
||||||
```
|
```
|
||||||
{% note %}
|
{% note %}
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
version: enterprise-server@3.1
|
version: ''
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"FEATURE_TEST_TRUE": true,
|
"FEATURE_TEST_TRUE": true,
|
||||||
"FEATURE_TEST_FALSE": false,
|
"FEATURE_TEST_FALSE": false,
|
||||||
"FEATURE_NEXTJS": false
|
"FEATURE_NEXTJS": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,13 @@ const { isConnectionDropped } = require('./halt-on-dropped-connection')
|
|||||||
const { nextHandleRequest } = require('./next')
|
const { nextHandleRequest } = require('./next')
|
||||||
|
|
||||||
const { HEROKU_RELEASE_VERSION, FEATURE_NEXTJS } = process.env
|
const { HEROKU_RELEASE_VERSION, FEATURE_NEXTJS } = process.env
|
||||||
|
|
||||||
|
const defaultNextJSRoutes = FEATURE_NEXTJS
|
||||||
|
? [
|
||||||
|
'/en/sponsors',
|
||||||
|
'/en/discussions'
|
||||||
|
]
|
||||||
|
: []
|
||||||
const pageCacheDatabaseNumber = 1
|
const pageCacheDatabaseNumber = 1
|
||||||
const pageCacheExpiration = 24 * 60 * 60 * 1000 // 24 hours
|
const pageCacheExpiration = 24 * 60 * 60 * 1000 // 24 hours
|
||||||
|
|
||||||
@@ -88,7 +95,7 @@ module.exports = async function renderPage (req, res, next) {
|
|||||||
const isRequestingJsonForDebugging = 'json' in req.query && process.env.NODE_ENV !== 'production'
|
const isRequestingJsonForDebugging = 'json' in req.query && process.env.NODE_ENV !== 'production'
|
||||||
|
|
||||||
// Should the current path be rendered by NextJS?
|
// Should the current path be rendered by NextJS?
|
||||||
const renderWithNextjs = 'nextjs' in req.query && FEATURE_NEXTJS
|
const renderWithNextjs = (defaultNextJSRoutes.includes(pathname) || 'nextjs' in req.query) && FEATURE_NEXTJS
|
||||||
|
|
||||||
// Is in an airgapped session?
|
// Is in an airgapped session?
|
||||||
const isAirgapped = Boolean(req.cookies.AIRGAP)
|
const isAirgapped = Boolean(req.cookies.AIRGAP)
|
||||||
|
|||||||
5
pages/[versionId]/[productId]/[...restPage]/index.tsx
Normal file
5
pages/[versionId]/[productId]/[...restPage]/index.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import GlobalPage from '../index'
|
||||||
|
|
||||||
|
export { getServerSideProps } from '../index'
|
||||||
|
|
||||||
|
export default GlobalPage
|
||||||
@@ -1,126 +1,61 @@
|
|||||||
import { GetServerSideProps } from 'next'
|
import { GetServerSideProps } from 'next'
|
||||||
import { Grid } from '@primer/components'
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
MainContextT,
|
MainContextT,
|
||||||
MainContext,
|
MainContext,
|
||||||
getMainContextFromRequest,
|
getMainContextFromRequest,
|
||||||
} from 'components/context/MainContext'
|
} from 'components/context/MainContext'
|
||||||
import { DefaultLayout } from 'components/DefaultLayout'
|
|
||||||
import {
|
import {
|
||||||
getProductLandingContextFromRequest,
|
getProductLandingContextFromRequest,
|
||||||
ProductLandingContextT,
|
ProductLandingContextT,
|
||||||
ProductLandingContext,
|
ProductLandingContext,
|
||||||
useProductLandingContext,
|
|
||||||
} from 'components/context/ProductLandingContext'
|
} from 'components/context/ProductLandingContext'
|
||||||
|
|
||||||
import { LandingHero } from 'components/landing/LandingHero'
|
import { ProductLanding } from 'components/landing/ProductLanding'
|
||||||
import { FeaturedArticles } from 'components/landing/FeaturedArticles'
|
import { TocLanding } from 'components/landing/TocLanding'
|
||||||
import { GuideCards } from 'components/landing/GuideCards'
|
import {
|
||||||
import { SponsorsExamples } from 'components/landing/SponsorsExamples'
|
getTocLandingContextFromRequest,
|
||||||
import { CommunityExamples } from 'components/landing/CommunityExamples'
|
TocLandingContext,
|
||||||
import { CodeExamples } from 'components/landing/CodeExamples'
|
TocLandingContextT,
|
||||||
import { LandingSection } from 'components/landing/LandingSection'
|
} from 'components/context/TocLandingContext'
|
||||||
import { useTranslation } from 'components/hooks/useTranslation'
|
|
||||||
import { ProductArticlesList } from 'components/landing/ProductArticlesList'
|
|
||||||
import { TableOfContents } from 'components/landing/TableOfContents'
|
|
||||||
import { ArticleVersionPicker } from 'components/article/ArticleVersionPicker'
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
mainContext: MainContextT
|
mainContext: MainContextT
|
||||||
productLandingContext: ProductLandingContextT
|
productLandingContext: ProductLandingContextT
|
||||||
|
tocLandingContext: TocLandingContextT
|
||||||
}
|
}
|
||||||
const ProductPage = ({ mainContext, productLandingContext }: Props) => {
|
const GlobalPage = ({ mainContext, productLandingContext, tocLandingContext }: Props) => {
|
||||||
return (
|
const { currentLayoutName, page, relativePath } = mainContext
|
||||||
<MainContext.Provider value={mainContext}>
|
|
||||||
|
let content
|
||||||
|
if (currentLayoutName === 'product-landing') {
|
||||||
|
content = (
|
||||||
<ProductLandingContext.Provider value={productLandingContext}>
|
<ProductLandingContext.Provider value={productLandingContext}>
|
||||||
{mainContext.currentLayoutName === 'product-landing' ? (
|
<ProductLanding />
|
||||||
<ProductLanding />
|
|
||||||
) : (
|
|
||||||
<TocProductLanding />
|
|
||||||
)}
|
|
||||||
</ProductLandingContext.Provider>
|
</ProductLandingContext.Provider>
|
||||||
</MainContext.Provider>
|
)
|
||||||
)
|
} else if (currentLayoutName === 'product-sublanding') {
|
||||||
|
content = <p>todo: product sub-landing</p>
|
||||||
|
} else if (relativePath?.endsWith('index.md')) {
|
||||||
|
content = (
|
||||||
|
<TocLandingContext.Provider value={tocLandingContext}>
|
||||||
|
<TocLanding
|
||||||
|
variant={
|
||||||
|
page.documentType === 'category' || relativePath === 'github/index.md'
|
||||||
|
? 'compact'
|
||||||
|
: 'expanded'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</TocLandingContext.Provider>
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
content = <p>article / fallback rendering</p>
|
||||||
|
}
|
||||||
|
|
||||||
|
return <MainContext.Provider value={mainContext}>{content}</MainContext.Provider>
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProductLanding = () => {
|
export default GlobalPage
|
||||||
const { title, guideCards, productUserExamples, productCommunityExamples, productCodeExamples } =
|
|
||||||
useProductLandingContext()
|
|
||||||
const { t } = useTranslation('product_landing')
|
|
||||||
|
|
||||||
return (
|
|
||||||
<DefaultLayout>
|
|
||||||
<LandingSection className="pt-3">
|
|
||||||
<LandingHero />
|
|
||||||
</LandingSection>
|
|
||||||
|
|
||||||
<LandingSection>
|
|
||||||
<FeaturedArticles />
|
|
||||||
</LandingSection>
|
|
||||||
|
|
||||||
{productCodeExamples.length > 0 && (
|
|
||||||
<LandingSection title={t('code_examples')} className="my-6">
|
|
||||||
<CodeExamples />
|
|
||||||
</LandingSection>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{productCommunityExamples.length > 0 && (
|
|
||||||
<LandingSection title={t('communities_using_discussions')} className="my-6">
|
|
||||||
<CommunityExamples />
|
|
||||||
</LandingSection>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{productUserExamples.length > 0 && (
|
|
||||||
<LandingSection title={t('sponsor_community')} className="my-6">
|
|
||||||
<SponsorsExamples />
|
|
||||||
</LandingSection>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{guideCards.length > 0 && (
|
|
||||||
<div className="color-bg-tertiary py-6 my-8">
|
|
||||||
<LandingSection title={t('guides')} className="my-6">
|
|
||||||
<GuideCards />
|
|
||||||
</LandingSection>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<LandingSection sectionLink="all-docs" title={`All ${title} Docs`}>
|
|
||||||
<ProductArticlesList />
|
|
||||||
</LandingSection>
|
|
||||||
</DefaultLayout>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const TocProductLanding = () => {
|
|
||||||
const { title, introPlainText, tocItems } = useProductLandingContext()
|
|
||||||
return (
|
|
||||||
<DefaultLayout>
|
|
||||||
<Grid
|
|
||||||
className="container-xl px-3 px-md-6 my-4 my-lg-4 container-xl "
|
|
||||||
gridTemplateColumns="minmax(500px, 720px) minmax(220px, 1fr)"
|
|
||||||
gridTemplateRows="auto 1fr"
|
|
||||||
gridGap={16}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<h1 className="my-4">{title}</h1>
|
|
||||||
<div className="lead-mktg">
|
|
||||||
<p>{introPlainText}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mt-7">
|
|
||||||
<TableOfContents items={tocItems} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<ArticleVersionPicker />
|
|
||||||
</div>
|
|
||||||
</Grid>
|
|
||||||
</DefaultLayout>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ProductPage
|
|
||||||
|
|
||||||
export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
|
export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
|
||||||
const req = context.req as any
|
const req = context.req as any
|
||||||
@@ -129,6 +64,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async (context) =>
|
|||||||
props: {
|
props: {
|
||||||
mainContext: getMainContextFromRequest(req),
|
mainContext: getMainContextFromRequest(req),
|
||||||
productLandingContext: getProductLandingContextFromRequest(req),
|
productLandingContext: getProductLandingContextFromRequest(req),
|
||||||
|
tocLandingContext: getTocLandingContextFromRequest(req),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import Head from 'next/head'
|
|||||||
import { useTheme, ThemeProvider } from '@primer/components'
|
import { useTheme, ThemeProvider } from '@primer/components'
|
||||||
import { getThemeProps } from 'components/lib/getThemeProps'
|
import { getThemeProps } from 'components/lib/getThemeProps'
|
||||||
|
|
||||||
import '@primer/css/index.scss'
|
import '../stylesheets/index.scss'
|
||||||
|
|
||||||
import { defaultThemeProps } from 'components/lib/getThemeProps'
|
import { defaultThemeProps } from 'components/lib/getThemeProps'
|
||||||
|
|
||||||
|
|||||||
@@ -39,3 +39,4 @@ $marketing-font-path: "/dist/fonts/";
|
|||||||
@import "tables.scss";
|
@import "tables.scss";
|
||||||
@import "toggle-images-button.scss";
|
@import "toggle-images-button.scss";
|
||||||
@import "underline-dashed.scss";
|
@import "underline-dashed.scss";
|
||||||
|
@import "utilities.scss";
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
/* Numbered procedures (step 1, step 2, ...)
|
/* Numbered procedures (step 1, step 2, ...)
|
||||||
------------------------------------------------------------------------------*/
|
------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
.list-style-inside {
|
||||||
|
list-style: inside;
|
||||||
|
}
|
||||||
|
|
||||||
.markdown-body ol {
|
.markdown-body ol {
|
||||||
counter-reset: li;
|
counter-reset: li;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
|
.opacity-0 {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
.opacity-60 {
|
.opacity-60 {
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
.opacity-70 {
|
.opacity-70 {
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
.opacity-100 {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|||||||
7
stylesheets/utilities.scss
Normal file
7
stylesheets/utilities.scss
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.transition-200 {
|
||||||
|
transition: 200ms
|
||||||
|
}
|
||||||
|
|
||||||
|
.rotate-180 {
|
||||||
|
transform: rotateX(180deg)
|
||||||
|
}
|
||||||
@@ -314,13 +314,13 @@ describe('nextjs query param', () => {
|
|||||||
|
|
||||||
it('conditionally renders through nextjs pipeline depending on FEATURE_NEXTJS value', async () => {
|
it('conditionally renders through nextjs pipeline depending on FEATURE_NEXTJS value', async () => {
|
||||||
const flagVal = require('../../feature-flags.json').FEATURE_NEXTJS
|
const flagVal = require('../../feature-flags.json').FEATURE_NEXTJS
|
||||||
await page.goto('http://localhost:4001/en/sponsors?nextjs=')
|
await page.goto('http://localhost:4001/en/actions?nextjs=')
|
||||||
const nextWrapper = await page.$('#__next')
|
const nextWrapper = await page.$('#__next')
|
||||||
flagVal === true ? expect(nextWrapper).toBeDefined() : expect(nextWrapper).toBeNull()
|
flagVal === true ? expect(nextWrapper).toBeDefined() : expect(nextWrapper).toBeNull()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('does not render through nextjs pipeline when nextjs query param is missing', async () => {
|
it('does not render through nextjs pipeline when nextjs query param is missing', async () => {
|
||||||
await page.goto('http://localhost:4001/en/sponsors')
|
await page.goto('http://localhost:4001/en/actions')
|
||||||
const nextWrapper = await page.$('#__next')
|
const nextWrapper = await page.$('#__next')
|
||||||
expect(nextWrapper).toBeNull()
|
expect(nextWrapper).toBeNull()
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user