Skip to content

Commit 324fc56

Browse files
authored
Merge branch 'main' into rc-ghes-3.10
2 parents d7a9d83 + 2f94cd7 commit 324fc56

File tree

259 files changed

+3231
-2133
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

259 files changed

+3231
-2133
lines changed

.github/actions-scripts/find-past-built-pr.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ async function main() {
2525
console.log('URL:', issue.html_url)
2626
number = issue.number
2727
if (number) {
28+
// We've found the issue (pull request), but before we accept
29+
// this `number`, check that the issue isn't locked.
30+
if (issue.locked) {
31+
number = ''
32+
}
2833
break
2934
}
3035
}
41.7 KB
Loading
46.5 KB
Loading

components/article/InArticlePicker.tsx

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useEffect, useState } from 'react'
22
import Cookies from 'components/lib/cookies'
3-
import { UnderlineNav } from '@primer/react'
3+
import { UnderlineNav } from '@primer/react/drafts'
44
import { sendEvent, EventType } from 'src/events/components/events'
55
import { useRouter } from 'next/router'
66

@@ -134,36 +134,35 @@ export const InArticlePicker = ({
134134
}
135135

136136
const sharedContainerProps = {
137-
'data-testid': `${queryStringKey}-picker`,
138137
'aria-label': ariaLabel,
139-
[`data-default-${queryStringKey}`]: defaultValue || '',
140-
className: 'mb-4',
141138
}
142139

143140
const params = new URLSearchParams(asPathQuery)
144141

145142
return (
146-
<UnderlineNav {...sharedContainerProps}>
147-
{options.map((option) => {
148-
params.set(queryStringKey, option.value)
149-
const linkProps = {
150-
[`data-${queryStringKey}`]: option.value,
151-
}
152-
return (
153-
<UnderlineNav.Link
154-
href={`?${params}`}
155-
key={option.value}
156-
selected={option.value === currentValue}
157-
onClick={(event) => {
158-
event.preventDefault()
159-
onClickChoice(option.value)
160-
}}
161-
{...linkProps}
162-
>
163-
{option.label}
164-
</UnderlineNav.Link>
165-
)
166-
})}
167-
</UnderlineNav>
143+
<div data-testid={`${queryStringKey}-picker`}>
144+
<UnderlineNav {...sharedContainerProps}>
145+
{options.map((option) => {
146+
params.set(queryStringKey, option.value)
147+
const linkProps = {
148+
[`data-${queryStringKey}`]: option.value,
149+
}
150+
return (
151+
<UnderlineNav.Item
152+
href={`?${params}`}
153+
key={option.value}
154+
aria-current={option.value === currentValue ? 'page' : undefined}
155+
onSelect={(event) => {
156+
event.preventDefault()
157+
onClickChoice(option.value)
158+
}}
159+
{...linkProps}
160+
>
161+
{option.label}
162+
</UnderlineNav.Item>
163+
)
164+
})}
165+
</UnderlineNav>
166+
</div>
168167
)
169168
}

components/article/PlatformPicker.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ function showPlatformSpecificContent(platform: string) {
2222
.filter((el) => platforms.some((platform) => el.classList.contains(platform.value)))
2323
.forEach((el) => {
2424
el.style.display = el.classList.contains(platform) ? '' : 'none'
25+
26+
// hack: special handling for minitoc links -- we can't pass the tool classes
27+
// directly to the Primer NavList.Item generated <li>, it gets passed down
28+
// to the child <a>. So if we find an <a> that has the tool class and its
29+
// parent is an <li>, we hide/unhide that element as well.
30+
if (el.tagName === 'A' && el.parentElement && el.parentElement.tagName === 'LI') {
31+
el.parentElement.style.display = el.classList.contains(platform) ? '' : 'none'
32+
}
2533
})
2634

2735
// find all platform-specific *inline* elements and hide or show as appropriate

components/hooks/useOnScreen.ts

Lines changed: 0 additions & 24 deletions
This file was deleted.

components/hooks/useUserLanguage.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { USER_LANGUAGE_COOKIE_NAME } from '../../lib/constants.js'
77

88
export function useUserLanguage() {
99
const { locale } = useRouter()
10-
const [userLanguage, setUserLanguage] = useState<string>('en')
10+
const [userLanguage, setUserLanguage] = useState('en')
1111
const { languages } = useLanguages()
1212

1313
useEffect(() => {
@@ -28,5 +28,10 @@ export function useUserLanguage() {
2828
}
2929
}, [locale])
3030

31-
return { userLanguage }
31+
function setUserLanguageCookie(language: string) {
32+
Cookies.set(USER_LANGUAGE_COOKIE_NAME, language)
33+
setUserLanguage(language)
34+
}
35+
36+
return { userLanguage, setUserLanguageCookie }
3237
}

components/page-header/HeaderNotifications.tsx

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useRouter } from 'next/router'
22
import cx from 'classnames'
3+
import { XIcon } from '@primer/octicons-react'
34

45
import { useLanguages } from 'components/context/LanguagesContext'
56
import { useMainContext } from 'components/context/MainContext'
@@ -18,12 +19,14 @@ enum NotificationType {
1819
type Notif = {
1920
content: string
2021
type?: NotificationType
22+
onClose?: () => void
2123
}
24+
2225
export const HeaderNotifications = () => {
2326
const router = useRouter()
2427
const { currentVersion } = useVersion()
2528
const { relativePath, allVersions, data, currentPathWithoutLanguage, page } = useMainContext()
26-
const { userLanguage } = useUserLanguage()
29+
const { userLanguage, setUserLanguageCookie } = useUserLanguage()
2730
const { languages } = useLanguages()
2831

2932
const { t } = useTranslation('header')
@@ -38,6 +41,18 @@ export const HeaderNotifications = () => {
3841
translationNotices.push({
3942
type: NotificationType.TRANSLATION,
4043
content: `This article is also available in <a href="${href}">${languages[userLanguage]?.name}</a>.`,
44+
onClose: () => {
45+
try {
46+
setUserLanguageCookie('en')
47+
} catch (err) {
48+
// You can never be too careful because setting a cookie
49+
// can fail. For example, some browser
50+
// extensions disallow all setting of cookies and attempts
51+
// at the `document.cookie` setter could throw. Just swallow
52+
// and move on.
53+
console.warn('Unable to set cookie', err)
54+
}
55+
},
4156
})
4257
}
4358
} else {
@@ -75,8 +90,9 @@ export const HeaderNotifications = () => {
7590

7691
return (
7792
<div>
78-
{allNotifications.map(({ type, content }, i) => {
93+
{allNotifications.map(({ type, content, onClose }, i) => {
7994
const isLast = i === allNotifications.length - 1
95+
8096
return (
8197
<div
8298
key={content}
@@ -91,8 +107,19 @@ export const HeaderNotifications = () => {
91107
type === NotificationType.EARLY_ACCESS && 'color-bg-danger',
92108
!isLast && 'border-bottom color-border-default',
93109
)}
94-
dangerouslySetInnerHTML={{ __html: content }}
95-
/>
110+
>
111+
{onClose && (
112+
<button
113+
className="flash-close js-flash-close"
114+
type="button"
115+
aria-label="Close"
116+
onClick={() => onClose()}
117+
>
118+
<XIcon size="small" className="octicon mr-1" />
119+
</button>
120+
)}
121+
<p dangerouslySetInnerHTML={{ __html: content }} />
122+
</div>
96123
)
97124
})}
98125
</div>

components/page-header/LanguagePicker.tsx

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,19 @@
11
import { useRouter } from 'next/router'
2-
import Cookies from 'components/lib/cookies'
32
import { GlobeIcon } from '@primer/octicons-react'
43

54
import { useLanguages } from 'components/context/LanguagesContext'
65
import { useTranslation } from 'components/hooks/useTranslation'
6+
import { useUserLanguage } from 'components/hooks/useUserLanguage'
77
import { Picker } from 'components/ui/Picker'
88

9-
import { USER_LANGUAGE_COOKIE_NAME } from '../../lib/constants.js'
10-
11-
function rememberPreferredLanguage(value: string) {
12-
try {
13-
// The reason we use a cookie and not local storage is because
14-
// this cookie value is used and needed by the server. For
15-
// example, when doing `GET /some/page` we need the cookie
16-
// to redirect to `Location: /ja/some/page`.
17-
// It's important it's *not* an HttpOnly cookie because we
18-
// need this in the client-side which is used to determine
19-
// the UI about displaying notifications about preferred
20-
// language if your cookie doesn't match the current URL.
21-
Cookies.set(USER_LANGUAGE_COOKIE_NAME, value)
22-
} catch (err) {
23-
// You can never be too careful because setting a cookie
24-
// can fail. For example, some browser
25-
// extensions disallow all setting of cookies and attempts
26-
// at the `document.cookie` setter could throw. Just swallow
27-
// and move on.
28-
console.warn('Unable to set preferred language cookie', err)
29-
}
30-
}
31-
329
type Props = {
3310
mediumOrLower?: boolean
3411
}
3512

3613
export const LanguagePicker = ({ mediumOrLower }: Props) => {
3714
const router = useRouter()
3815
const { languages } = useLanguages()
16+
const { setUserLanguageCookie } = useUserLanguage()
3917

4018
const locale = router.locale || 'en'
4119

@@ -74,7 +52,18 @@ export const LanguagePicker = ({ mediumOrLower }: Props) => {
7452
pickerLabel={mediumOrLower ? 'Language' : ''}
7553
iconButton={mediumOrLower ? undefined : GlobeIcon}
7654
onSelect={(item) => {
77-
if (item.extra?.locale) rememberPreferredLanguage(item.extra.locale)
55+
if (item.extra?.locale) {
56+
try {
57+
setUserLanguageCookie(item.extra.locale)
58+
} catch (err) {
59+
// You can never be too careful because setting a cookie
60+
// can fail. For example, some browser
61+
// extensions disallow all setting of cookies and attempts
62+
// at the `document.cookie` setter could throw. Just swallow
63+
// and move on.
64+
console.warn('Unable to set preferred language cookie', err)
65+
}
66+
}
7867
}}
7968
buttonBorder={mediumOrLower}
8069
dataTestId="default-language"

components/release-notes/GHAEReleaseNotePatch.tsx

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,25 @@
1-
import { useRef, useEffect } from 'react'
1+
import { useRef } from 'react'
22
import dayjs from 'dayjs'
33
import cx from 'classnames'
44

55
import { useTranslation } from 'components/hooks/useTranslation'
6-
import { useOnScreen } from 'components/hooks/useOnScreen'
76
import { PatchNotes } from './PatchNotes'
87
import { CurrentVersion, ReleaseNotePatch } from './types'
98

109
import styles from './PatchNotes.module.scss'
1110

12-
type Props = { patch: ReleaseNotePatch; currentVersion: CurrentVersion; didEnterView: () => void }
13-
export function GHAEReleaseNotePatch({ patch, currentVersion, didEnterView }: Props) {
11+
type Props = { patch: ReleaseNotePatch; currentVersion: CurrentVersion }
12+
export function GHAEReleaseNotePatch({ patch, currentVersion }: Props) {
1413
const { t } = useTranslation('release_notes')
1514
const containerRef = useRef<HTMLDivElement>(null)
16-
const onScreen = useOnScreen(containerRef, { rootMargin: '-40% 0px -50%' })
17-
useEffect(() => {
18-
if (onScreen) {
19-
didEnterView()
20-
}
21-
}, [onScreen])
22-
2315
const bannerText = t('banner_text')
2416

2517
return (
26-
<div
27-
ref={containerRef}
28-
className={cx(styles.sectionHeading, 'mb-10 pb-6 border-bottom border-top')}
29-
id={patch.release}
30-
>
31-
<header style={{ zIndex: 1 }} className="container-xl border-bottom px-3 pt-4 pb-2">
18+
<div ref={containerRef} className={cx(styles.sectionHeading, 'mb-10 pb-6')} id={patch.release}>
19+
<header
20+
style={{ zIndex: 1, marginTop: -1 }}
21+
className="container-xl border-top border-bottom px-3 pt-4 pb-2"
22+
>
3223
<div className="d-flex flex-items-center">
3324
<h2 className="border-bottom-0 m-0 p-0">
3425
{currentVersion.versionTitle} {patch.release}

0 commit comments

Comments
 (0)