Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 41 additions & 21 deletions components/article/PlatformPicker.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react'
import { useCallback, useEffect, useState } from 'react'
import Cookies from 'js-cookie'
import { SubNav, TabNav, UnderlineNav } from '@primer/react'
import { sendEvent, EventType } from 'components/lib/events'
Expand All @@ -7,6 +7,7 @@ import { useRouter } from 'next/router'
import { useArticleContext } from 'components/context/ArticleContext'
import { parseUserAgent } from 'components/lib/user-agent'

const platformQueryKey = 'platform'
const platforms = [
{ id: 'mac', label: 'Mac' },
{ id: 'windows', label: 'Windows' },
Expand Down Expand Up @@ -49,9 +50,10 @@ type Props = {
variant?: 'subnav' | 'tabnav' | 'underlinenav'
}
export const PlatformPicker = ({ variant = 'subnav' }: Props) => {
const router = useRouter()
const { query, asPath } = router
const { defaultPlatform, detectedPlatforms } = useArticleContext()
const [currentPlatform, setCurrentPlatform] = useState(defaultPlatform || '')
const { asPath } = useRouter()

// Run on mount for client-side only features
useEffect(() => {
Expand All @@ -60,7 +62,15 @@ export const PlatformPicker = ({ variant = 'subnav' }: Props) => {
userAgent = 'mac'
}

const platform = defaultPlatform || Cookies.get('osPreferred') || userAgent || 'linux'
// If it's a valid platform option, set platform from query param
let platform =
query[platformQueryKey] && Array.isArray(query[platformQueryKey])
? query[platformQueryKey][0]
: query[platformQueryKey] || ''
if (!platform || !platforms.some((platform) => platform.id === query.platform)) {
platform = defaultPlatform || Cookies.get('osPreferred') || userAgent || 'linux'
}

setCurrentPlatform(platform)

// always trigger this on initial render. if the default doesn't change the other useEffect won't fire
Expand All @@ -75,23 +85,28 @@ export const PlatformPicker = ({ variant = 'subnav' }: Props) => {
}
}, [currentPlatform, detectedPlatforms.join(',')])

const onClickPlatform = (platform: string) => {
setCurrentPlatform(platform)

// imperatively modify the article content
showPlatformSpecificContent(platform)

sendEvent({
type: EventType.preference,
preference_name: 'os',
preference_value: platform,
})

Cookies.set('osPreferred', platform, {
sameSite: 'strict',
secure: true,
})
}
const onClickPlatform = useCallback(
(platform: string) => {
// Set platform in query param without altering other query params
const [pathRoot, pathQuery = ''] = asPath.split('?')
const params = new URLSearchParams(pathQuery)
params.set(platformQueryKey, platform)
router.push({ pathname: pathRoot, query: params.toString() }, undefined, { shallow: true })

sendEvent({
type: EventType.preference,
preference_name: 'os',
preference_value: platform,
})

Cookies.set('osPreferred', platform, {
sameSite: 'strict',
secure: document.location.protocol !== 'http:',
expires: 365,
})
},
[asPath]
)

// only show platforms that are in the current article
const platformOptions = platforms.filter((platform) => detectedPlatforms.includes(platform.id))
Expand Down Expand Up @@ -128,15 +143,20 @@ export const PlatformPicker = ({ variant = 'subnav' }: Props) => {
}

if (variant === 'underlinenav') {
const [, pathQuery = ''] = asPath.split('?')
const params = new URLSearchParams(pathQuery)
return (
<UnderlineNav {...sharedContainerProps}>
{platformOptions.map((option) => {
params.set(platformQueryKey, option.id)
return (
<UnderlineNav.Link
href={`?${params.toString()}`}
key={option.id}
data-platform={option.id}
selected={option.id === currentPlatform}
onClick={() => {
onClick={(event) => {
event.preventDefault()
onClickPlatform(option.id)
}}
>
Expand Down
78 changes: 54 additions & 24 deletions components/article/ToolPicker.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react'
import { useCallback, useEffect, useState } from 'react'
import { useRouter } from 'next/router'
import Cookies from 'js-cookie'
import { UnderlineNav } from '@primer/react'
Expand Down Expand Up @@ -47,11 +47,13 @@ function getDefaultTool(defaultTool: string | undefined, detectedTools: Array<st
return detectedTools[0]
}

const toolQueryKey = 'tool'
type Props = {
variant?: 'subnav' | 'tabnav' | 'underlinenav'
}
export const ToolPicker = ({ variant = 'subnav' }: Props) => {
const { asPath } = useRouter()
const router = useRouter()
const { asPath, query } = router
// allTools comes from the ArticleContext which contains the list of tools available
const { defaultTool, detectedTools, allTools } = useArticleContext()
const [currentTool, setCurrentTool] = useState(getDefaultTool(defaultTool, detectedTools))
Expand All @@ -73,38 +75,66 @@ export const ToolPicker = ({ variant = 'subnav' }: Props) => {
}
}, [])

// Whenever the currentTool is changed, update the article content
// Whenever the currentTool is changed, update the article content or selected tool from query param
useEffect(() => {
preserveAnchorNodePosition(document, () => {
showToolSpecificContent(currentTool, Object.keys(allTools))
})

// If tool from query is a valid option, use it
const tool =
query[toolQueryKey] && Array.isArray(query[toolQueryKey])
? query[toolQueryKey][0]
: query[toolQueryKey] || ''
if (tool && detectedTools.includes(tool)) {
setCurrentTool(tool)
}
}, [currentTool, asPath])

function onClickTool(tool: string) {
setCurrentTool(tool)
sendEvent({
type: EventType.preference,
preference_name: 'application',
preference_value: tool,
})
Cookies.set('toolPreferred', tool, { sameSite: 'strict', secure: true })
}
const onClickTool = useCallback(
(tool: string) => {
// Set tool in query param without altering other query params
const [pathRoot, pathQuery = ''] = asPath.split('?')
const params = new URLSearchParams(pathQuery)
params.set(toolQueryKey, tool)
router.push({ pathname: pathRoot, query: params.toString() }, undefined, { shallow: true })

sendEvent({
type: EventType.preference,
preference_name: 'application',
preference_value: tool,
})
Cookies.set('toolPreferred', tool, {
sameSite: 'strict',
secure: document.location.protocol !== 'http:',
expires: 365,
})
},
[asPath]
)

if (variant === 'underlinenav') {
const [, pathQuery = ''] = asPath.split('?')
const params = new URLSearchParams(pathQuery)
return (
<UnderlineNav {...sharedContainerProps}>
{detectedTools.map((tool) => (
<UnderlineNav.Link
key={tool}
data-tool={tool}
selected={tool === currentTool}
onClick={() => {
onClickTool(tool)
}}
>
{allTools[tool]}
</UnderlineNav.Link>
))}
{detectedTools.map((tool) => {
params.set(toolQueryKey, tool)
return (
<UnderlineNav.Link
href={`?${params.toString()}`}
key={tool}
data-tool={tool}
selected={tool === currentTool}
onClick={(event) => {
event.preventDefault()
onClickTool(tool)
}}
>
{allTools[tool]}
</UnderlineNav.Link>
)
})}
</UnderlineNav>
)
}
Expand Down
2 changes: 1 addition & 1 deletion components/lib/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function getUserEventsId() {
if (cookieValue) return cookieValue
cookieValue = uuidv4()
Cookies.set(COOKIE_NAME, cookieValue, {
secure: true,
secure: document.location.protocol !== 'http:',
sameSite: 'strict',
expires: 365,
})
Expand Down
2 changes: 1 addition & 1 deletion components/rest/RestCodeSamples.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export function RestCodeSamples({ operation, slug }: Props) {
setSelectedLanguage(languageKey)
Cookies.set('codeSampleLanguagePreferred', languageKey, {
sameSite: 'strict',
secure: true,
secure: document.location.protocol !== 'http:',
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ You can enable or disable features for all repositories.

{% data reusables.advanced-security.note-org-enable-uses-seats %}

{% ifversion ghes or ghec or ghae %}
{% note %}

**Note:** If you encounter an error that reads "GitHub Advanced Security cannot be enabled because of a policy setting for the organization," contact your enterprise admin and ask them to change the GitHub Advanced Security policy for your enterprise. For more information, see "[Enforcing policies for Advanced Security in your enterprise](/admin/policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-code-security-and-analysis-for-your-enterprise)."
{% endnote %}
{% endif %}

1. Go to the security and analysis settings for your organization. For more information, see "[Displaying the security and analysis settings](#displaying-the-security-and-analysis-settings)."
2. Under "Code security and analysis", to the right of the feature, click **Disable all** or **Enable all**. {% ifversion ghes or ghec %}The control for "{% data variables.product.prodname_GH_advanced_security %}" is disabled if you have no available seats in your {% data variables.product.prodname_GH_advanced_security %} license.{% endif %}
{% ifversion fpt %}
Expand Down Expand Up @@ -88,7 +95,7 @@ You can enable or disable features for all repositories.

{% endif %}
{% ifversion ghae or ghes %}
3. Click **Enable/Disable all** or **Enable/Disable for eligible repositories** to confirm the change.
5. Click **Enable/Disable all** or **Enable/Disable for eligible repositories** to confirm the change.
![Button to enable feature for all the eligible repositories in the organization](/assets/images/enterprise/github-ae/organizations/security-and-analysis-enable-secret-scanning-existing-repos-ghae.png)
{% endif %}

Expand Down