@@ -45,7 +45,7 @@ export const DefaultLayout = (props: Props) => {
|
|||||||
</Head>
|
</Head>
|
||||||
<SidebarNav />
|
<SidebarNav />
|
||||||
|
|
||||||
<main className="width-full">
|
<main className="flex-1 min-width-0">
|
||||||
<Header />
|
<Header />
|
||||||
<DeprecationBanner />
|
<DeprecationBanner />
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ export const Header = () => {
|
|||||||
const showVersionPicker =
|
const showVersionPicker =
|
||||||
relativePath === 'index.md' ||
|
relativePath === 'index.md' ||
|
||||||
currentLayoutName === 'product-landing' ||
|
currentLayoutName === 'product-landing' ||
|
||||||
currentLayoutName === 'product-sublanding'
|
currentLayoutName === 'product-sublanding' ||
|
||||||
|
currentLayoutName === 'release-notes'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="border-bottom color-border-secondary no-print">
|
<div className="border-bottom color-border-secondary no-print">
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ export const HeaderNotifications = () => {
|
|||||||
const isLast = i === allNotifications.length - 1
|
const isLast = i === allNotifications.length - 1
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
key={content}
|
||||||
className={cx(
|
className={cx(
|
||||||
'header-notifications text-center f5 color-text-primary py-4 px-6',
|
'header-notifications text-center f5 color-text-primary py-4 px-6',
|
||||||
type === NotificationType.TRANSLATION && 'translation_notice color-bg-info',
|
type === NotificationType.TRANSLATION && 'translation_notice color-bg-info',
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ type EnterpriseServerReleases = {
|
|||||||
isOldestReleaseDeprecated: boolean
|
isOldestReleaseDeprecated: boolean
|
||||||
oldestSupported: string
|
oldestSupported: string
|
||||||
nextDeprecationDate: string
|
nextDeprecationDate: string
|
||||||
|
supported: Array<string>
|
||||||
}
|
}
|
||||||
export type MainContextT = {
|
export type MainContextT = {
|
||||||
breadcrumbs: {
|
breadcrumbs: {
|
||||||
@@ -154,6 +155,7 @@ export const getMainContextFromRequest = (req: any): MainContextT => {
|
|||||||
'isOldestReleaseDeprecated',
|
'isOldestReleaseDeprecated',
|
||||||
'oldestSupported',
|
'oldestSupported',
|
||||||
'nextDeprecationDate',
|
'nextDeprecationDate',
|
||||||
|
'supported',
|
||||||
]),
|
]),
|
||||||
enterpriseServerVersions: req.context.enterpriseServerVersions,
|
enterpriseServerVersions: req.context.enterpriseServerVersions,
|
||||||
currentLanguage: req.context.currentLanguage,
|
currentLanguage: req.context.currentLanguage,
|
||||||
|
|||||||
@@ -52,6 +52,12 @@ export type ProductLandingContextT = {
|
|||||||
changelogUrl?: string
|
changelogUrl?: string
|
||||||
whatsNewChangelog?: Array<{ href: string; title: string; date: string }>
|
whatsNewChangelog?: Array<{ href: string; title: string; date: string }>
|
||||||
tocItems: Array<TocItem>
|
tocItems: Array<TocItem>
|
||||||
|
releases: Array<{
|
||||||
|
version: string
|
||||||
|
firstPreviousRelease: string
|
||||||
|
secondPreviousRelease: string
|
||||||
|
patches: Array<{ date: string; version: string }>
|
||||||
|
}>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ProductLandingContext = createContext<ProductLandingContextT | null>(null)
|
export const ProductLandingContext = createContext<ProductLandingContextT | null>(null)
|
||||||
@@ -89,6 +95,7 @@ export const getProductLandingContextFromRequest = (req: any): ProductLandingCon
|
|||||||
changelogUrl: req.context.changelogUrl || [],
|
changelogUrl: req.context.changelogUrl || [],
|
||||||
productCodeExamples: req.context.productCodeExamples || [],
|
productCodeExamples: req.context.productCodeExamples || [],
|
||||||
productCommunityExamples: req.context.productCommunityExamples || [],
|
productCommunityExamples: req.context.productCommunityExamples || [],
|
||||||
|
releases: req.context.releases || [],
|
||||||
|
|
||||||
productUserExamples: (req.context.productUserExamples || []).map(
|
productUserExamples: (req.context.productUserExamples || []).map(
|
||||||
({ user, description }: any) => ({
|
({ user, description }: any) => ({
|
||||||
|
|||||||
25
components/hooks/useOnScreen.tsx
Normal file
25
components/hooks/useOnScreen.tsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { useState, useEffect, MutableRefObject, RefObject } from 'react'
|
||||||
|
|
||||||
|
export function useOnScreen<T extends Element>(
|
||||||
|
ref: MutableRefObject<T | undefined> | RefObject<T>,
|
||||||
|
rootMargin: string = '0px'
|
||||||
|
): boolean {
|
||||||
|
const [isIntersecting, setIntersecting] = useState(false)
|
||||||
|
useEffect(() => {
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
([entry]) => {
|
||||||
|
setIntersecting(entry.isIntersecting)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rootMargin,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (ref.current) {
|
||||||
|
observer.observe(ref.current)
|
||||||
|
}
|
||||||
|
return () => {
|
||||||
|
ref.current && observer.unobserve(ref.current)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
return isIntersecting
|
||||||
|
}
|
||||||
@@ -3,10 +3,15 @@ import { useRouter } from 'next/router'
|
|||||||
type VersionInfo = {
|
type VersionInfo = {
|
||||||
currentVersion: string
|
currentVersion: string
|
||||||
isEnterprise: boolean
|
isEnterprise: boolean
|
||||||
|
isEnterpriseServer: boolean
|
||||||
}
|
}
|
||||||
const DEFAULT_VERSION = 'free-pro-team@latest'
|
const DEFAULT_VERSION = 'free-pro-team@latest'
|
||||||
export const useVersion = (): VersionInfo => {
|
export const useVersion = (): VersionInfo => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const currentVersion = (router.query.versionId as string) || DEFAULT_VERSION
|
const currentVersion = (router.query.versionId as string) || DEFAULT_VERSION
|
||||||
return { currentVersion, isEnterprise: currentVersion.includes('enterprise') }
|
return {
|
||||||
|
currentVersion,
|
||||||
|
isEnterprise: currentVersion.includes('enterprise'),
|
||||||
|
isEnterpriseServer: currentVersion.includes('enterprise-server'),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,13 @@ import { CodeExamples } from 'components/landing/CodeExamples'
|
|||||||
import { LandingSection } from 'components/landing/LandingSection'
|
import { LandingSection } from 'components/landing/LandingSection'
|
||||||
import { useTranslation } from 'components/hooks/useTranslation'
|
import { useTranslation } from 'components/hooks/useTranslation'
|
||||||
import { ProductArticlesList } from 'components/landing/ProductArticlesList'
|
import { ProductArticlesList } from 'components/landing/ProductArticlesList'
|
||||||
|
import { ProductReleases } from 'components/landing/ProductReleases'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
import { useVersion } from 'components/hooks/useVersion'
|
||||||
|
|
||||||
export const ProductLanding = () => {
|
export const ProductLanding = () => {
|
||||||
|
const router = useRouter()
|
||||||
|
const { isEnterpriseServer } = useVersion()
|
||||||
const {
|
const {
|
||||||
shortTitle,
|
shortTitle,
|
||||||
guideCards,
|
guideCards,
|
||||||
@@ -49,9 +54,11 @@ export const ProductLanding = () => {
|
|||||||
</LandingSection>
|
</LandingSection>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* {% if currentVersion contains 'enterprise-server' and currentProduct == 'admin' %}
|
{router.query.productId === 'admin' && isEnterpriseServer && (
|
||||||
{% include product-releases %}
|
<LandingSection title={t('supported_releases')} className="my-6">
|
||||||
{% endif %} */}
|
<ProductReleases />
|
||||||
|
</LandingSection>
|
||||||
|
)}
|
||||||
|
|
||||||
{guideCards.length > 0 && (
|
{guideCards.length > 0 && (
|
||||||
<div className="color-bg-tertiary py-6 my-8">
|
<div className="color-bg-tertiary py-6 my-8">
|
||||||
|
|||||||
68
components/landing/ProductReleases.tsx
Normal file
68
components/landing/ProductReleases.tsx
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import { ArrowRightIcon, ArrowUpIcon, FileIcon, ListUnorderedIcon } from '@primer/octicons-react'
|
||||||
|
import { useMainContext } from 'components/context/MainContext'
|
||||||
|
import { useProductLandingContext } from 'components/context/ProductLandingContext'
|
||||||
|
import { useTranslation } from 'components/hooks/useTranslation'
|
||||||
|
import { Link } from 'components/Link'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
|
export function ProductReleases() {
|
||||||
|
const { t } = useTranslation('product_landing')
|
||||||
|
const router = useRouter()
|
||||||
|
const { enterpriseServerReleases, allVersions } = useMainContext()
|
||||||
|
const { releases } = useProductLandingContext()
|
||||||
|
const currentPath = router.asPath.split('?')[0]
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="d-lg-flex gutter-lg flex-items-stretch">
|
||||||
|
{releases.map((release) => {
|
||||||
|
const releaseNumber = release.version
|
||||||
|
if (!enterpriseServerReleases.supported.includes(releaseNumber)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const releaseVersion = `enterprise-server@${releaseNumber}`
|
||||||
|
const latestPatch = release.patches[0]
|
||||||
|
const firstPreviousVersion = `enterprise-server@${release.firstPreviousRelease}`
|
||||||
|
const secondPreviousVersion = `enterprise-server@${release.secondPreviousRelease}`
|
||||||
|
return (
|
||||||
|
<div key={releaseNumber} className="col-lg-4 col-12 mb-3">
|
||||||
|
<div className="Box color-shadow-medium height-full d-block hover-shadow-large no-underline color-text-primary p-5">
|
||||||
|
<h2>{allVersions[releaseVersion].versionTitle}</h2>
|
||||||
|
<p className="mt-2 mb-4 color-text-tertiary">
|
||||||
|
<ListUnorderedIcon />{' '}
|
||||||
|
<Link
|
||||||
|
href={`/${router.locale}/${releaseVersion}/admin/release-notes#${latestPatch.version}`}
|
||||||
|
>
|
||||||
|
{t('release_notes_for')} {latestPatch.version}
|
||||||
|
</Link>{' '}
|
||||||
|
({latestPatch.date})
|
||||||
|
</p>
|
||||||
|
<p className="mt-2 mb-4 color-text-tertiary">
|
||||||
|
<ArrowUpIcon /> {t('upgrade_from')}{' '}
|
||||||
|
<Link
|
||||||
|
href={`/${router.locale}/${firstPreviousVersion}/admin/enterprise-management/upgrading-github-enterprise-server`}
|
||||||
|
>
|
||||||
|
{release.firstPreviousRelease}
|
||||||
|
</Link>{' '}
|
||||||
|
or{' '}
|
||||||
|
<Link
|
||||||
|
href={`/${router.locale}/${secondPreviousVersion}/admin/enterprise-management/upgrading-github-enterprise-server`}
|
||||||
|
>
|
||||||
|
{release.secondPreviousRelease}
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
|
<p className="mt-2 mb-4 color-text-tertiary">
|
||||||
|
<FileIcon />{' '}
|
||||||
|
<Link href={`/${router.locale}/${releaseVersion}`}>{t('browse_all_docs')}</Link>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Link href={`${currentPath}/release-notes}`} className="btn btn-outline float-right">
|
||||||
|
{t('explore_release_notes')} <ArrowRightIcon />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
59
components/release-notes/GHAEReleaseNotePatch.tsx
Normal file
59
components/release-notes/GHAEReleaseNotePatch.tsx
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { useRef, useEffect } from 'react'
|
||||||
|
|
||||||
|
import { useTranslation } from 'components/hooks/useTranslation'
|
||||||
|
import { useOnScreen } from 'components/hooks/useOnScreen'
|
||||||
|
import { PatchNotes } from './PatchNotes'
|
||||||
|
import { ReleaseNotePatch } from './types'
|
||||||
|
|
||||||
|
type Props = { patch: ReleaseNotePatch; didEnterView: () => void }
|
||||||
|
export function GHAEReleaseNotePatch({ patch, didEnterView }: Props) {
|
||||||
|
const { t } = useTranslation('release_notes')
|
||||||
|
const containerRef = useRef<HTMLDivElement>(null)
|
||||||
|
const onScreen = useOnScreen(containerRef, '-40% 0px -50%')
|
||||||
|
useEffect(() => {
|
||||||
|
if (onScreen) {
|
||||||
|
didEnterView()
|
||||||
|
}
|
||||||
|
}, [onScreen])
|
||||||
|
|
||||||
|
const bannerText = patch.currentWeek
|
||||||
|
? t('banner_text_current')
|
||||||
|
: `${t('banner_text_past')} ${patch.friendlyDate}.`
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={containerRef}
|
||||||
|
className="mb-10 color-bg-secondary pb-6 border-bottom border-top"
|
||||||
|
id={patch.date}
|
||||||
|
>
|
||||||
|
<header
|
||||||
|
style={{ zIndex: 1 }}
|
||||||
|
className="container-xl position-sticky top-0 color-bg-secondary border-bottom px-3 pt-4 pb-2"
|
||||||
|
>
|
||||||
|
<div className="d-flex flex-items-center">
|
||||||
|
<h2 className="border-bottom-0 m-0 p-0">{patch.title}</h2>
|
||||||
|
|
||||||
|
{patch.release_candidate && (
|
||||||
|
<span
|
||||||
|
className="IssueLabel color-bg-warning-inverse color-text-inverse ml-3"
|
||||||
|
style={{ whiteSpace: 'pre' }}
|
||||||
|
>
|
||||||
|
Release Candidate
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<button className="js-print btn-link ml-3 text-small text-bold">Print</button>
|
||||||
|
</div>
|
||||||
|
<p className="color-text-secondary mt-1">
|
||||||
|
{patch.friendlyDate} - {bannerText}
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div className="container-xl px-3">
|
||||||
|
<div className="mt-3" dangerouslySetInnerHTML={{ __html: patch.intro }} />
|
||||||
|
|
||||||
|
<PatchNotes patch={patch} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
89
components/release-notes/GHAEReleaseNotes.tsx
Normal file
89
components/release-notes/GHAEReleaseNotes.tsx
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import { useState } from 'react'
|
||||||
|
import cx from 'classnames'
|
||||||
|
import { ChevronDownIcon } from '@primer/octicons-react'
|
||||||
|
import { GHAEReleaseNotePatch } from './GHAEReleaseNotePatch'
|
||||||
|
import { GHAEReleaseNotesContextT } from './types'
|
||||||
|
|
||||||
|
type GitHubAEProps = {
|
||||||
|
context: GHAEReleaseNotesContextT
|
||||||
|
}
|
||||||
|
export function GHAEReleaseNotes({ context }: GitHubAEProps) {
|
||||||
|
const { releaseNotes, releases, currentVersion } = context
|
||||||
|
const [focusedPatch, setFocusedPatch] = useState('')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="d-flex">
|
||||||
|
<article className="min-width-0 flex-1">
|
||||||
|
<div className="d-flex flex-items-center flex-justify-between color-bg-primary px-5 py-2">
|
||||||
|
<div></div>
|
||||||
|
<h1 className="f4 py-3 m-0">{currentVersion.planTitle} release notes</h1>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="markdown-body">
|
||||||
|
{releaseNotes.map((patch) => {
|
||||||
|
return (
|
||||||
|
<GHAEReleaseNotePatch
|
||||||
|
key={patch.version}
|
||||||
|
patch={patch}
|
||||||
|
didEnterView={() => setFocusedPatch(patch.version)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<aside
|
||||||
|
className="markdown-body position-sticky top-0 d-none d-md-block border-left no-print color-bg-primary flex-shrink-0"
|
||||||
|
style={{ width: 260, height: '100vh' }}
|
||||||
|
>
|
||||||
|
<nav className="height-full overflow-auto">
|
||||||
|
<ul className="list-style-none pl-0 text-bold">
|
||||||
|
{releases.map((release) => {
|
||||||
|
return (
|
||||||
|
<li key={release.version} className="border-bottom">
|
||||||
|
<details
|
||||||
|
className="my-0 details-reset release-notes-version-picker"
|
||||||
|
aria-current="page"
|
||||||
|
open
|
||||||
|
>
|
||||||
|
<summary className="px-3 py-4 my-0 d-flex flex-items-center flex-justify-between">
|
||||||
|
{release.version}
|
||||||
|
<div className="d-flex">
|
||||||
|
<span className="color-text-tertiary text-mono text-small text-normal mr-1">
|
||||||
|
{release.patches.length} releases
|
||||||
|
</span>
|
||||||
|
<ChevronDownIcon />
|
||||||
|
</div>
|
||||||
|
</summary>
|
||||||
|
<ul className="color-bg-tertiary border-top list-style-none py-4 px-0 my-0">
|
||||||
|
{release.patches.map((patch) => {
|
||||||
|
const isActive = patch.version === focusedPatch
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
key={patch.version}
|
||||||
|
className={cx(
|
||||||
|
'js-release-notes-patch-link px-3 my-0 py-1',
|
||||||
|
isActive && 'selected'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href={`#${patch.date}`}
|
||||||
|
className="d-flex flex-items-center flex-justify-between"
|
||||||
|
>
|
||||||
|
{patch.friendlyDate}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
110
components/release-notes/GHESReleaseNotePatch.tsx
Normal file
110
components/release-notes/GHESReleaseNotePatch.tsx
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
import { useEffect, useRef } from 'react'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
|
||||||
|
import { useTranslation } from 'components/hooks/useTranslation'
|
||||||
|
import { PatchNotes } from './PatchNotes'
|
||||||
|
import { Link } from 'components/Link'
|
||||||
|
import { CurrentVersion, ReleaseNotePatch, GHESMessage } from './types'
|
||||||
|
import { useOnScreen } from 'components/hooks/useOnScreen'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
patch: ReleaseNotePatch
|
||||||
|
currentVersion: CurrentVersion
|
||||||
|
latestPatch: string
|
||||||
|
latestRelease: string
|
||||||
|
message: GHESMessage
|
||||||
|
didEnterView: () => void
|
||||||
|
}
|
||||||
|
export function GHESReleaseNotePatch({
|
||||||
|
patch,
|
||||||
|
currentVersion,
|
||||||
|
latestPatch,
|
||||||
|
latestRelease,
|
||||||
|
message,
|
||||||
|
didEnterView,
|
||||||
|
}: Props) {
|
||||||
|
const { t } = useTranslation('header')
|
||||||
|
const containerRef = useRef<HTMLDivElement>(null)
|
||||||
|
const onScreen = useOnScreen(containerRef, '-40% 0px -50%')
|
||||||
|
useEffect(() => {
|
||||||
|
if (onScreen) {
|
||||||
|
didEnterView()
|
||||||
|
}
|
||||||
|
}, [onScreen])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={containerRef}
|
||||||
|
className="mb-10 color-bg-secondary pb-6 border-bottom border-top"
|
||||||
|
id={patch.version}
|
||||||
|
>
|
||||||
|
<header
|
||||||
|
style={{ zIndex: 1 }}
|
||||||
|
className="container-xl position-sticky top-0 color-bg-secondary border-bottom px-3 pt-4 pb-2"
|
||||||
|
>
|
||||||
|
<div className="d-flex flex-items-center">
|
||||||
|
<h2 className="border-bottom-0 m-0 p-0">
|
||||||
|
{currentVersion.versionTitle}.{patch.patchVersion}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
{patch.release_candidate && (
|
||||||
|
<span
|
||||||
|
className="IssueLabel color-bg-warning-inverse color-text-inverse ml-3"
|
||||||
|
style={{ whiteSpace: 'pre' }}
|
||||||
|
>
|
||||||
|
Release Candidate
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{currentVersion.plan == 'enterprise-server' && (
|
||||||
|
<Link
|
||||||
|
href={`https://enterprise.github.com/releases/${patch.downloadVersion}/download`}
|
||||||
|
className="ml-3 text-small text-bold"
|
||||||
|
>
|
||||||
|
Download
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<button className="js-print btn-link ml-3 text-small text-bold">Print</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="color-text-secondary mt-1">{dayjs(patch.date).format('MMMM, DD, YYYY')}</p>
|
||||||
|
|
||||||
|
{patch.version !== latestPatch && currentVersion.currentRelease === latestRelease && (
|
||||||
|
<p className="color-text-secondary mt-1">
|
||||||
|
<span
|
||||||
|
dangerouslySetInnerHTML={{ __html: message.ghes_release_notes_upgrade_patch_only }}
|
||||||
|
/>{' '}
|
||||||
|
{t('notices.release_notes_use_latest')}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{patch.version === latestPatch && currentVersion.currentRelease !== latestRelease && (
|
||||||
|
<p className="color-text-secondary mt-1">
|
||||||
|
<span
|
||||||
|
dangerouslySetInnerHTML={{ __html: message.ghes_release_notes_upgrade_release_only }}
|
||||||
|
/>{' '}
|
||||||
|
{t('notices.release_notes_use_latest')}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{patch.version !== latestPatch && currentVersion.currentRelease !== latestRelease && (
|
||||||
|
<p className="color-text-secondary mt-1">
|
||||||
|
<span
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: message.ghes_release_notes_upgrade_patch_and_release,
|
||||||
|
}}
|
||||||
|
/>{' '}
|
||||||
|
{t('notices.release_notes_use_latest')}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div className="container-xl px-3">
|
||||||
|
<div className="mt-3" dangerouslySetInnerHTML={{ __html: patch.intro }} />
|
||||||
|
|
||||||
|
<PatchNotes patch={patch} withReleaseNoteLabel />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
170
components/release-notes/GHESReleaseNotes.tsx
Normal file
170
components/release-notes/GHESReleaseNotes.tsx
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
import { useState } from 'react'
|
||||||
|
import cx from 'classnames'
|
||||||
|
import {
|
||||||
|
ChevronDownIcon,
|
||||||
|
ChevronLeftIcon,
|
||||||
|
ChevronRightIcon,
|
||||||
|
LinkExternalIcon,
|
||||||
|
} from '@primer/octicons-react'
|
||||||
|
import { useMainContext } from 'components/context/MainContext'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
|
||||||
|
import { Link } from 'components/Link'
|
||||||
|
import { GHESReleaseNotesContextT } from './types'
|
||||||
|
import { GHESReleaseNotePatch } from './GHESReleaseNotePatch'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
context: GHESReleaseNotesContextT
|
||||||
|
}
|
||||||
|
export function GHESReleaseNotes({ context }: Props) {
|
||||||
|
const { currentLanguage, currentProduct } = useMainContext()
|
||||||
|
const [focusedPatch, setFocusedPatch] = useState('')
|
||||||
|
const {
|
||||||
|
prevRelease,
|
||||||
|
nextRelease,
|
||||||
|
latestPatch,
|
||||||
|
latestRelease,
|
||||||
|
currentVersion,
|
||||||
|
releaseNotes,
|
||||||
|
releases,
|
||||||
|
message,
|
||||||
|
} = context
|
||||||
|
return (
|
||||||
|
<div className="d-flex">
|
||||||
|
<article className="min-width-0 flex-1">
|
||||||
|
<div className="d-flex flex-items-center flex-justify-between color-bg-primary text-bold px-5 py-2">
|
||||||
|
{prevRelease ? (
|
||||||
|
<Link
|
||||||
|
className="btn btn-outline"
|
||||||
|
href={`/${currentLanguage}/${currentVersion.plan}@${prevRelease}/${currentProduct}/release-notes`}
|
||||||
|
>
|
||||||
|
<ChevronLeftIcon /> {prevRelease}
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div />
|
||||||
|
)}
|
||||||
|
|
||||||
|
<h1 className="f4 py-3 m-0">
|
||||||
|
{currentVersion.planTitle} {currentVersion.currentRelease} release notes
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
{nextRelease ? (
|
||||||
|
<Link
|
||||||
|
className="btn btn-outline"
|
||||||
|
href={`/${currentLanguage}/${currentVersion.plan}@${nextRelease}/${currentProduct}/release-notes`}
|
||||||
|
>
|
||||||
|
{nextRelease} <ChevronRightIcon />
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="markdown-body">
|
||||||
|
{releaseNotes.map((patch) => {
|
||||||
|
return (
|
||||||
|
<GHESReleaseNotePatch
|
||||||
|
key={patch.version}
|
||||||
|
patch={patch}
|
||||||
|
currentVersion={currentVersion}
|
||||||
|
latestPatch={latestPatch}
|
||||||
|
latestRelease={latestRelease}
|
||||||
|
message={message}
|
||||||
|
didEnterView={() => {
|
||||||
|
setFocusedPatch(patch.version)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<aside
|
||||||
|
className="markdown-body position-sticky top-0 d-none d-md-block border-left no-print color-bg-primary flex-shrink-0"
|
||||||
|
style={{ width: 260, height: '100vh' }}
|
||||||
|
>
|
||||||
|
<nav className="height-full overflow-auto">
|
||||||
|
<ul className="list-style-none pl-0 text-bold">
|
||||||
|
{releases.map((release) => {
|
||||||
|
const releaseLink = `/${currentLanguage}/${currentVersion.plan}@${release.version}/${currentProduct?.id}/release-notes`
|
||||||
|
|
||||||
|
if (!release.patches || release.patches.length === 0) {
|
||||||
|
return (
|
||||||
|
<li key={release.version} className="border-bottom">
|
||||||
|
<Link
|
||||||
|
href={releaseLink}
|
||||||
|
className="Link--primary no-underline px-3 py-4 my-0 d-flex flex-items-center flex-justify-between"
|
||||||
|
>
|
||||||
|
{release.version}
|
||||||
|
<LinkExternalIcon />
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (release.version === currentVersion.currentRelease) {
|
||||||
|
return (
|
||||||
|
<li key={release.version} className="border-bottom">
|
||||||
|
<details
|
||||||
|
className="my-0 details-reset release-notes-version-picker"
|
||||||
|
aria-current="page"
|
||||||
|
open
|
||||||
|
>
|
||||||
|
<summary className="px-3 py-4 my-0 d-flex flex-items-center flex-justify-between">
|
||||||
|
{release.version}
|
||||||
|
<div className="d-flex">
|
||||||
|
<span className="color-text-tertiary text-mono text-small text-normal mr-1">
|
||||||
|
{release.patches.length} releases
|
||||||
|
</span>
|
||||||
|
<ChevronDownIcon />
|
||||||
|
</div>
|
||||||
|
</summary>
|
||||||
|
<ul className="color-bg-tertiary border-top list-style-none py-4 px-0 my-0">
|
||||||
|
{release.patches.map((patch) => {
|
||||||
|
const isActive = patch.version === focusedPatch
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
key={patch.version}
|
||||||
|
className={cx(
|
||||||
|
'js-release-notes-patch-link px-3 my-0 py-1',
|
||||||
|
isActive && 'selected'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
href={`${releaseLink}#${patch.version}`}
|
||||||
|
className="d-flex flex-items-center flex-justify-between"
|
||||||
|
>
|
||||||
|
{patch.version}
|
||||||
|
<span className="color-text-tertiary text-mono text-small text-normal">
|
||||||
|
{dayjs(patch.date).format('MMMM DD, YYYY')}
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li key={release.version} className="border-bottom">
|
||||||
|
<Link
|
||||||
|
className="px-3 py-4 my-0 d-flex flex-items-center flex-justify-between"
|
||||||
|
href={releaseLink}
|
||||||
|
>
|
||||||
|
{release.version}
|
||||||
|
<span className="color-text-tertiary text-mono text-small text-normal mr-1">
|
||||||
|
{release.patches.length} releases
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
84
components/release-notes/PatchNotes.tsx
Normal file
84
components/release-notes/PatchNotes.tsx
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
import cx from 'classnames'
|
||||||
|
import slugger from 'github-slugger'
|
||||||
|
import { ReleaseNotePatch } from './types'
|
||||||
|
import { Link } from 'components/Link'
|
||||||
|
|
||||||
|
const SectionToLabelMap: Record<string, string> = {
|
||||||
|
features: 'Features',
|
||||||
|
bugs: 'Bug fixes',
|
||||||
|
known_issues: 'Known issues',
|
||||||
|
security_fixes: 'Security fixes',
|
||||||
|
changes: 'Changes',
|
||||||
|
deprecations: 'Deprecations',
|
||||||
|
backups: 'Backups',
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
patch: ReleaseNotePatch
|
||||||
|
withReleaseNoteLabel?: boolean
|
||||||
|
}
|
||||||
|
export function PatchNotes({ patch, withReleaseNoteLabel }: Props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{Object.entries(patch.sections).map(([key, sectionItems], i, arr) => {
|
||||||
|
const isLast = i === arr.length - 1
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={key}
|
||||||
|
className={cx(
|
||||||
|
`release-notes-section-${key}`,
|
||||||
|
'py-6 d-block d-xl-flex gutter-xl flex-items-baseline',
|
||||||
|
!withReleaseNoteLabel && 'mx-6',
|
||||||
|
!isLast && 'border-bottom'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{withReleaseNoteLabel && (
|
||||||
|
<div className="col-12 col-xl-3 mb-5">
|
||||||
|
<span className="px-3 py-2 text-small text-bold text-uppercase text-mono color-text-inverse release-notes-section-label">
|
||||||
|
{SectionToLabelMap[key] || 'INVALID SECTION'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<ul className={cx(withReleaseNoteLabel && 'col-xl-9', 'col-12 release-notes-list')}>
|
||||||
|
{sectionItems.map((item) => {
|
||||||
|
if (typeof item === 'string') {
|
||||||
|
return (
|
||||||
|
<li key={item} className="release-notes-list-item">
|
||||||
|
<span dangerouslySetInnerHTML={{ __html: item }} />
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const slug = item.heading ? slugger.slug(item.heading) : ''
|
||||||
|
return (
|
||||||
|
<li key={slug} className="release-notes-list-item list-style-none">
|
||||||
|
<h4
|
||||||
|
id={slug}
|
||||||
|
className="release-notes-section-heading text-uppercase text-bold"
|
||||||
|
>
|
||||||
|
<Link href={`#${slug}`} className="text-inherit">
|
||||||
|
{item.heading}
|
||||||
|
</Link>
|
||||||
|
</h4>
|
||||||
|
|
||||||
|
<ul className="pl-0 pb-4 mt-2 release-notes-list">
|
||||||
|
{item.notes.map((note) => {
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
key={note}
|
||||||
|
className="release-notes-list-item"
|
||||||
|
dangerouslySetInnerHTML={{ __html: note }}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
49
components/release-notes/types.ts
Normal file
49
components/release-notes/types.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
export type CurrentVersion = {
|
||||||
|
plan: string
|
||||||
|
planTitle: string
|
||||||
|
versionTitle: string
|
||||||
|
currentRelease: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GHESMessage = {
|
||||||
|
ghes_release_notes_upgrade_patch_only: string
|
||||||
|
ghes_release_notes_upgrade_release_only: string
|
||||||
|
ghes_release_notes_upgrade_patch_and_release: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReleaseNoteSection =
|
||||||
|
| {
|
||||||
|
heading?: string
|
||||||
|
notes: Array<string>
|
||||||
|
}
|
||||||
|
| string
|
||||||
|
|
||||||
|
export type ReleaseNotePatch = {
|
||||||
|
patchVersion: string
|
||||||
|
version: string
|
||||||
|
downloadVersion: string
|
||||||
|
intro: string
|
||||||
|
date: string
|
||||||
|
friendlyDate: string
|
||||||
|
title: string
|
||||||
|
release_candidate?: boolean
|
||||||
|
currentWeek: boolean
|
||||||
|
sections: Record<string, Array<ReleaseNoteSection>>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GHAEReleaseNotesContextT = {
|
||||||
|
releaseNotes: Array<ReleaseNotePatch>
|
||||||
|
releases: Array<{ version: string; patches: Array<ReleaseNotePatch> }>
|
||||||
|
currentVersion: CurrentVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GHESReleaseNotesContextT = {
|
||||||
|
latestPatch: string
|
||||||
|
prevRelease?: string
|
||||||
|
nextRelease?: string
|
||||||
|
latestRelease: string
|
||||||
|
currentVersion: CurrentVersion
|
||||||
|
releaseNotes: Array<ReleaseNotePatch>
|
||||||
|
releases: Array<{ version: string; patches: Array<ReleaseNotePatch> }>
|
||||||
|
message: GHESMessage
|
||||||
|
}
|
||||||
@@ -20,9 +20,9 @@ header:
|
|||||||
early_access: 📣 Please <b>do not share</b> this URL publicly. This page contains content about an early access feature.
|
early_access: 📣 Please <b>do not share</b> this URL publicly. This page contains content about an early access feature.
|
||||||
release_notes_use_latest: Please use the latest release for the latest security, performance, and bug fixes.
|
release_notes_use_latest: Please use the latest release for the latest security, performance, and bug fixes.
|
||||||
# GHES release notes
|
# GHES release notes
|
||||||
ghes_release_notes_upgrade_patch_only: 📣 This is not the <a href="#{{ latestPatch }}">latest patch release</a> of Enterprise Server. {% data ui.header.notices.release_notes_use_latest %}
|
ghes_release_notes_upgrade_patch_only: 📣 This is not the <a href="#{{ latestPatch }}">latest patch release</a> of Enterprise Server.
|
||||||
ghes_release_notes_upgrade_release_only: 📣 This is not the <a href="/enterprise-server@{{ latestRelease }}/admin/release-notes">latest release</a> of Enterprise Server. {% data ui.header.notices.release_notes_use_latest %}
|
ghes_release_notes_upgrade_release_only: 📣 This is not the <a href="/enterprise-server@{{ latestRelease }}/admin/release-notes">latest release</a> of Enterprise Server.
|
||||||
ghes_release_notes_upgrade_patch_and_release: 📣 This is not the <a href="#{{ latestPatch }}">latest patch release</a> of this release series, and this is not the <a href="/enterprise-server@{{ latestRelease }}/admin/release-notes">latest release</a> of Enterprise Server. {% data ui.header.notices.release_notes_use_latest %}
|
ghes_release_notes_upgrade_patch_and_release: 📣 This is not the <a href="#{{ latestPatch }}">latest patch release</a> of this release series, and this is not the <a href="/enterprise-server@{{ latestRelease }}/admin/release-notes">latest release</a> of Enterprise Server.
|
||||||
release_notes:
|
release_notes:
|
||||||
banner_text_current: These changes will roll out over the next one week.
|
banner_text_current: These changes will roll out over the next one week.
|
||||||
banner_text_past: These changes rolled out to enterprises during the week of
|
banner_text_past: These changes rolled out to enterprises during the week of
|
||||||
|
|||||||
@@ -54,15 +54,15 @@
|
|||||||
<p class="color-text-secondary mt-1">{{ patch.date | date: "%B %d, %Y" }}</p>
|
<p class="color-text-secondary mt-1">{{ patch.date | date: "%B %d, %Y" }}</p>
|
||||||
|
|
||||||
{% if patch.version != latestPatch and currentVersionObject.currentRelease == latestRelease %}
|
{% if patch.version != latestPatch and currentVersionObject.currentRelease == latestRelease %}
|
||||||
<p class="color-text-secondary mt-1">{% data ui.header.notices.ghes_release_notes_upgrade_patch_only %}</p>
|
<p class="color-text-secondary mt-1">{% data ui.header.notices.ghes_release_notes_upgrade_patch_only %} {% data ui.header.notices.release_notes_use_latest %}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if patch.version == latestPatch and currentVersionObject.currentRelease != latestRelease %}
|
{% if patch.version == latestPatch and currentVersionObject.currentRelease != latestRelease %}
|
||||||
<p class="color-text-secondary mt-1">{% data ui.header.notices.ghes_release_notes_upgrade_release_only %}</p>
|
<p class="color-text-secondary mt-1">{% data ui.header.notices.ghes_release_notes_upgrade_release_only %} {% data ui.header.notices.release_notes_use_latest %}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if patch.version != latestPatch and currentVersionObject.currentRelease != latestRelease %}
|
{% if patch.version != latestPatch and currentVersionObject.currentRelease != latestRelease %}
|
||||||
<p class="color-text-secondary mt-1">{% data ui.header.notices.ghes_release_notes_upgrade_patch_and_release %}</p>
|
<p class="color-text-secondary mt-1">{% data ui.header.notices.ghes_release_notes_upgrade_patch_and_release %} {% data ui.header.notices.release_notes_use_latest %}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export default function releaseNotes () {
|
export default function releaseNotes () {
|
||||||
|
if (window.next) return
|
||||||
const patches = Array.from(document.querySelectorAll('.js-release-notes-patch'))
|
const patches = Array.from(document.querySelectorAll('.js-release-notes-patch'))
|
||||||
if (patches.length === 0) return
|
if (patches.length === 0) return
|
||||||
|
|
||||||
|
|||||||
13
package-lock.json
generated
13
package-lock.json
generated
@@ -93,6 +93,7 @@
|
|||||||
"@graphql-inspector/core": "^2.5.0",
|
"@graphql-inspector/core": "^2.5.0",
|
||||||
"@graphql-tools/load": "^6.2.8",
|
"@graphql-tools/load": "^6.2.8",
|
||||||
"@octokit/rest": "^18.5.3",
|
"@octokit/rest": "^18.5.3",
|
||||||
|
"@types/github-slugger": "^1.3.0",
|
||||||
"@types/lodash": "^4.14.169",
|
"@types/lodash": "^4.14.169",
|
||||||
"@types/react": "^17.0.6",
|
"@types/react": "^17.0.6",
|
||||||
"@types/react-dom": "^17.0.5",
|
"@types/react-dom": "^17.0.5",
|
||||||
@@ -4040,6 +4041,12 @@
|
|||||||
"integrity": "sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg==",
|
"integrity": "sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg==",
|
||||||
"devOptional": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/github-slugger": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/github-slugger/-/github-slugger-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-J/rMZa7RqiH/rT29TEVZO4nBoDP9XJOjnbbIofg7GQKs4JIduEO3WLpte+6WeUz/TcrXKlY+bM7FYrp8yFB+3g==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/graceful-fs": {
|
"node_modules/@types/graceful-fs": {
|
||||||
"version": "4.1.5",
|
"version": "4.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
|
||||||
@@ -27663,6 +27670,12 @@
|
|||||||
"integrity": "sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg==",
|
"integrity": "sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg==",
|
||||||
"devOptional": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
|
"@types/github-slugger": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/github-slugger/-/github-slugger-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-J/rMZa7RqiH/rT29TEVZO4nBoDP9XJOjnbbIofg7GQKs4JIduEO3WLpte+6WeUz/TcrXKlY+bM7FYrp8yFB+3g==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/graceful-fs": {
|
"@types/graceful-fs": {
|
||||||
"version": "4.1.5",
|
"version": "4.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
|
||||||
|
|||||||
@@ -99,6 +99,7 @@
|
|||||||
"@graphql-inspector/core": "^2.5.0",
|
"@graphql-inspector/core": "^2.5.0",
|
||||||
"@graphql-tools/load": "^6.2.8",
|
"@graphql-tools/load": "^6.2.8",
|
||||||
"@octokit/rest": "^18.5.3",
|
"@octokit/rest": "^18.5.3",
|
||||||
|
"@types/github-slugger": "^1.3.0",
|
||||||
"@types/lodash": "^4.14.169",
|
"@types/lodash": "^4.14.169",
|
||||||
"@types/react": "^17.0.6",
|
"@types/react": "^17.0.6",
|
||||||
"@types/react-dom": "^17.0.5",
|
"@types/react-dom": "^17.0.5",
|
||||||
|
|||||||
81
pages/[versionId]/admin/release-notes.tsx
Normal file
81
pages/[versionId]/admin/release-notes.tsx
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import { GetServerSideProps } from 'next'
|
||||||
|
import { Liquid } from 'liquidjs'
|
||||||
|
|
||||||
|
const liquid = new Liquid()
|
||||||
|
|
||||||
|
import {
|
||||||
|
MainContextT,
|
||||||
|
MainContext,
|
||||||
|
getMainContextFromRequest,
|
||||||
|
} from 'components/context/MainContext'
|
||||||
|
import { DefaultLayout } from 'components/DefaultLayout'
|
||||||
|
import { GHAEReleaseNotes } from 'components/release-notes/GHAEReleaseNotes'
|
||||||
|
import { GHESReleaseNotes } from 'components/release-notes/GHESReleaseNotes'
|
||||||
|
import {
|
||||||
|
CurrentVersion,
|
||||||
|
GHAEReleaseNotesContextT,
|
||||||
|
GHESReleaseNotesContextT,
|
||||||
|
} from 'components/release-notes/types'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
mainContext: MainContextT
|
||||||
|
ghaeContext: GHAEReleaseNotesContextT
|
||||||
|
ghesContext: GHESReleaseNotesContextT
|
||||||
|
currentVersion: CurrentVersion
|
||||||
|
}
|
||||||
|
export default function ReleaseNotes({
|
||||||
|
mainContext,
|
||||||
|
ghesContext,
|
||||||
|
ghaeContext,
|
||||||
|
currentVersion,
|
||||||
|
}: Props) {
|
||||||
|
return (
|
||||||
|
<MainContext.Provider value={mainContext}>
|
||||||
|
<DefaultLayout>
|
||||||
|
{currentVersion.plan === 'enterprise-server' && <GHESReleaseNotes context={ghesContext} />}
|
||||||
|
|
||||||
|
{currentVersion.plan === 'github-ae' && <GHAEReleaseNotes context={ghaeContext} />}
|
||||||
|
</DefaultLayout>
|
||||||
|
</MainContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
|
||||||
|
const req = context.req as any
|
||||||
|
const currentVersion = req.context.allVersions[req.context.currentVersion]
|
||||||
|
const { latestPatch = '', latestRelease = '' } = req.context
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
mainContext: getMainContextFromRequest(req),
|
||||||
|
currentVersion,
|
||||||
|
ghesContext: {
|
||||||
|
currentVersion,
|
||||||
|
latestPatch,
|
||||||
|
latestRelease,
|
||||||
|
prevRelease: req.context.prevRelease || '',
|
||||||
|
nextRelease: req.context.nextRelease || '',
|
||||||
|
releaseNotes: req.context.releaseNotes,
|
||||||
|
releases: req.context.releases,
|
||||||
|
message: {
|
||||||
|
ghes_release_notes_upgrade_patch_only: liquid.parseAndRenderSync(
|
||||||
|
req.context.site.data.ui.header.notices.ghes_release_notes_upgrade_patch_only,
|
||||||
|
{ latestPatch, latestRelease }
|
||||||
|
),
|
||||||
|
ghes_release_notes_upgrade_release_only: liquid.parseAndRenderSync(
|
||||||
|
req.context.site.data.ui.header.notices.ghes_release_notes_upgrade_release_only,
|
||||||
|
{ latestPatch, latestRelease }
|
||||||
|
),
|
||||||
|
ghes_release_notes_upgrade_patch_and_release: liquid.parseAndRenderSync(
|
||||||
|
req.context.site.data.ui.header.notices.ghes_release_notes_upgrade_patch_and_release,
|
||||||
|
{ latestPatch, latestRelease }
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ghaeContext: {
|
||||||
|
currentVersion,
|
||||||
|
releaseNotes: req.context.releaseNotes,
|
||||||
|
releases: req.context.releases,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,10 @@ ul.release-notes-list li.release-notes-list-item {
|
|||||||
|
|
||||||
.release-notes-section-heading {
|
.release-notes-section-heading {
|
||||||
font-size: 15px !important;
|
font-size: 15px !important;
|
||||||
|
scroll-margin-top: 280px !important;
|
||||||
|
@include breakpoint(sm) {
|
||||||
|
scroll-margin-top: 200px !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
details[open].release-notes-version-picker
|
details[open].release-notes-version-picker
|
||||||
@@ -36,7 +40,7 @@ $colors-list: (
|
|||||||
security_fixes: var(--color-auto-pink-5),
|
security_fixes: var(--color-auto-pink-5),
|
||||||
changes: var(--color-auto-green-5),
|
changes: var(--color-auto-green-5),
|
||||||
deprecations: var(--color-auto-purple-5),
|
deprecations: var(--color-auto-purple-5),
|
||||||
backups: var(--color-auto-orange-5)
|
backups: var(--color-auto-orange-5),
|
||||||
);
|
);
|
||||||
|
|
||||||
@each $key, $val in $colors-list {
|
@each $key, $val in $colors-list {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
|
"allowSyntheticDefaultImports": true
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules"],
|
"exclude": ["node_modules"],
|
||||||
"include": ["*.d.ts", "**/*.ts", "**/*.tsx"]
|
"include": ["*.d.ts", "**/*.ts", "**/*.tsx"]
|
||||||
|
|||||||
Reference in New Issue
Block a user