Merge branch 'main' into andrekolodochka-patch-2
@@ -119,6 +119,7 @@ async function run() {
|
||||
const statusID = findFieldID('Status', data)
|
||||
const featureID = findFieldID('Feature', data)
|
||||
const contributorTypeID = findFieldID('Contributor type', data)
|
||||
const sizeTypeID = findFieldID('Size', data)
|
||||
const authorID = findFieldID('Author', data)
|
||||
|
||||
// Get the ID of the single select values that we want to set
|
||||
@@ -169,6 +170,8 @@ async function run() {
|
||||
reviewDueDateID: reviewDueDateID,
|
||||
contributorTypeID: contributorTypeID,
|
||||
contributorType: contributorType,
|
||||
sizeTypeID: sizeTypeID,
|
||||
sizeType: '', // Although we aren't populating size, we are passing the variable so that we can use the shared mutation function
|
||||
featureID: featureID,
|
||||
authorID: authorID,
|
||||
headers: {
|
||||
|
||||
7
.github/actions-scripts/projects.js
vendored
@@ -186,6 +186,8 @@ export function generateUpdateProjectNextItemFieldMutation({
|
||||
$reviewDueDateID: ID!
|
||||
$contributorTypeID: ID!
|
||||
$contributorType: String!
|
||||
$sizeTypeID: ID!
|
||||
$sizeType: String!
|
||||
$featureID: ID!
|
||||
$authorID: ID!
|
||||
) {
|
||||
@@ -211,6 +213,11 @@ export function generateUpdateProjectNextItemFieldMutation({
|
||||
fieldID: '$contributorTypeID',
|
||||
value: '$contributorType',
|
||||
})}
|
||||
${generateMutationToUpdateField({
|
||||
item: item,
|
||||
fieldID: '$sizeTypeID',
|
||||
value: '$sizeType',
|
||||
})}
|
||||
${generateMutationToUpdateField({
|
||||
item: item,
|
||||
fieldID: '$featureID',
|
||||
|
||||
119
.github/actions-scripts/ready-for-docs-review.js
vendored
@@ -12,7 +12,7 @@ async function run() {
|
||||
// Get info about the docs-content review board project
|
||||
const data = await graphql(
|
||||
`
|
||||
query ($organization: String!, $projectNumber: Int!) {
|
||||
query ($organization: String!, $projectNumber: Int!, $id: ID!) {
|
||||
organization(login: $organization) {
|
||||
projectNext(number: $projectNumber) {
|
||||
id
|
||||
@@ -25,9 +25,22 @@ async function run() {
|
||||
}
|
||||
}
|
||||
}
|
||||
item: node(id: $id) {
|
||||
__typename
|
||||
... on PullRequest {
|
||||
files(first: 100) {
|
||||
nodes {
|
||||
additions
|
||||
deletions
|
||||
path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
{
|
||||
id: process.env.ITEM_NODE_ID,
|
||||
organization: process.env.ORGANIZATION,
|
||||
projectNumber: parseInt(process.env.PROJECT_NUMBER),
|
||||
headers: {
|
||||
@@ -46,6 +59,7 @@ async function run() {
|
||||
const statusID = findFieldID('Status', data)
|
||||
const featureID = findFieldID('Feature', data)
|
||||
const contributorTypeID = findFieldID('Contributor type', data)
|
||||
const sizeTypeID = findFieldID('Size', data)
|
||||
const authorID = findFieldID('Author', data)
|
||||
|
||||
// Get the ID of the single select values that we want to set
|
||||
@@ -53,22 +67,115 @@ async function run() {
|
||||
const hubberTypeID = findSingleSelectID('Hubber or partner', 'Contributor type', data)
|
||||
const docsMemberTypeID = findSingleSelectID('Docs team', 'Contributor type', data)
|
||||
const osContributorTypeID = findSingleSelectID('OS contributor', 'Contributor type', data)
|
||||
const sizeXS = findSingleSelectID('XS', 'Size', data)
|
||||
const sizeS = findSingleSelectID('S', 'Size', data)
|
||||
const sizeM = findSingleSelectID('M', 'Size', data)
|
||||
const sizeL = findSingleSelectID('L', 'Size', data)
|
||||
|
||||
// Add the PR to the project
|
||||
const newItemID = await addItemToProject(process.env.PR_NODE_ID, projectID)
|
||||
const newItemID = await addItemToProject(process.env.ITEM_NODE_ID, projectID)
|
||||
|
||||
// If the item is a PR, determine the feature and size
|
||||
let feature = ''
|
||||
let sizeType = '' // You don't need to use a field ID if you want the value to be empty
|
||||
if (data.item.__typename === 'PullRequest') {
|
||||
// Get the
|
||||
// - number of files changed
|
||||
// - total number of additions/deletions
|
||||
// - affected docs sets (not considering changes to data/assets)
|
||||
let numFiles = 0
|
||||
let numChanges = 0
|
||||
let features = new Set([])
|
||||
const files = data.item.files.nodes.forEach((node) => {
|
||||
numFiles += 1
|
||||
numChanges += node.additions
|
||||
numChanges += node.deletions
|
||||
// To determine the feature, we are only looking at `content/*` paths
|
||||
// and then pulling out the second part of the path, which corresponds to the docs set
|
||||
const pathComponents = node.path.split('/')
|
||||
if (pathComponents[0] === 'content') {
|
||||
features.add(pathComponents[1])
|
||||
}
|
||||
})
|
||||
|
||||
// Determine the size
|
||||
if (numFiles < 5 && numChanges < 25) {
|
||||
sizeType = sizeXS
|
||||
} else if (numFiles < 5 && numChanges < 25) {
|
||||
sizeType = sizeS
|
||||
} else if (numFiles < 5 && numChanges < 25) {
|
||||
sizeType = sizeM
|
||||
} else {
|
||||
sizeType = sizeL
|
||||
}
|
||||
|
||||
// Set the feature
|
||||
feature = Array.from(features).join()
|
||||
}
|
||||
|
||||
// If this is the OS repo, determine if this is a first time contributor
|
||||
// If yes, set the author to 'first time contributor' instead of to the author login
|
||||
let firstTimeContributor
|
||||
if (process.env.REPO === 'github/docs') {
|
||||
const contributorData = await graphql(
|
||||
`
|
||||
query ($author: String!) {
|
||||
user(login: $author) {
|
||||
contributionsCollection {
|
||||
pullRequestContributionsByRepository {
|
||||
contributions {
|
||||
totalCount
|
||||
}
|
||||
repository {
|
||||
nameWithOwner
|
||||
}
|
||||
}
|
||||
issueContributionsByRepository {
|
||||
contributions {
|
||||
totalCount
|
||||
}
|
||||
repository {
|
||||
nameWithOwner
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
{
|
||||
author: process.env.AUTHOR_LOGIN,
|
||||
headers: {
|
||||
authorization: `token ${process.env.TOKEN}`,
|
||||
},
|
||||
}
|
||||
)
|
||||
const prCount =
|
||||
contributorData.user.contributionsCollection.pullRequestContributionsByRepository.filter(
|
||||
(item) => item.repository.nameWithOwner === 'github/docs'
|
||||
)[0].contributions.totalCount
|
||||
const issueCount =
|
||||
contributorData.user.contributionsCollection.issueContributionsByRepository.filter(
|
||||
(item) => item.repository.nameWithOwner === 'github/docs'
|
||||
)[0].contributions.totalCount
|
||||
|
||||
if (prCount + issueCount <= 1) {
|
||||
firstTimeContributor = true
|
||||
}
|
||||
}
|
||||
const turnaround = process.env.REPO === 'github/docs' ? 3 : 2
|
||||
// Generate a mutation to populate fields for the new project item
|
||||
const updateProjectNextItemMutation = generateUpdateProjectNextItemFieldMutation({
|
||||
item: newItemID,
|
||||
author: process.env.AUTHOR_LOGIN,
|
||||
turnaround: 2,
|
||||
author: firstTimeContributor ? 'first time contributor' : process.env.AUTHOR_LOGIN,
|
||||
turnaround: turnaround,
|
||||
feature: feature,
|
||||
})
|
||||
|
||||
// Determine which variable to use for the contributor type
|
||||
let contributorType
|
||||
if (await isDocsTeamMember(process.env.AUTHOR_LOGIN)) {
|
||||
contributorType = docsMemberTypeID
|
||||
} else if (process.env.PR_REPO === 'github/docs') {
|
||||
} else if (process.env.REPO === 'github/docs') {
|
||||
contributorType = osContributorTypeID
|
||||
} else {
|
||||
contributorType = hubberTypeID
|
||||
@@ -84,6 +191,8 @@ async function run() {
|
||||
reviewDueDateID: reviewDueDateID,
|
||||
contributorTypeID: contributorTypeID,
|
||||
contributorType: contributorType,
|
||||
sizeTypeID: sizeTypeID,
|
||||
sizeType: sizeType,
|
||||
featureID: featureID,
|
||||
authorID: authorID,
|
||||
headers: {
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
transfer-issue:
|
||||
name: Transfer issue
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.label.name == 'rest-description' && github.repository == 'github/docs'
|
||||
if: (github.event.label.name == 'rest-description' || github.event.label.name == 'graphql-description') && github.repository == 'github/docs'
|
||||
steps:
|
||||
- name: Check if this run was triggered by a member of the docs team
|
||||
uses: actions/github-script@2b34a689ec86a68d8ab9478298f91d5401337b7d
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
OLD_ISSUE: ${{ github.event.issue.html_url }}
|
||||
|
||||
- name: Comment on the old issue
|
||||
run: gh issue comment $OLD_ISSUE --body "Thank you for opening this issue! Updates to the REST API description must be made internally. I have copied your issue to an internal issue, so I will close this issue."
|
||||
run: gh issue comment $OLD_ISSUE --body "Thank you for opening this issue! Updates to the REST/GraphQL API description must be made internally. I have copied your issue to an internal issue, so I will close this issue."
|
||||
env:
|
||||
GITHUB_TOKEN: ${{secrets.DOCUBOT_READORG_REPO_WORKFLOW_SCOPES}}
|
||||
OLD_ISSUE: ${{ github.event.issue.html_url }}
|
||||
|
||||
68
.github/workflows/os-ready-for-review.yml
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
name: OS Ready for review
|
||||
|
||||
# **What it does**: Adds pull requests and issues in the docs repository to the docs-content review board when the "waiting for review" label is added
|
||||
# **Why we have it**: So that contributors in the OS repo can easily get reviews from the docs-content team, and so that writers can see when a PR is ready for review
|
||||
# **Who does it impact**: Writers working in the docs repository
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [labeled]
|
||||
issues:
|
||||
types: [labeled]
|
||||
|
||||
jobs:
|
||||
request_doc_review:
|
||||
name: Request a review from the docs-content team
|
||||
if: github.event.label.name == 'waiting for review' && github.repository == 'github/docs'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Exit if not triggered by a docs team member
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.DOCUBOT_READORG_REPO_WORKFLOW_SCOPES }}
|
||||
run: |
|
||||
members="$( gh api graphql -f query='
|
||||
query {
|
||||
organization(login: "github") {
|
||||
team(slug: "docs") {
|
||||
members {
|
||||
nodes {
|
||||
login
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
' --jq '.data.organization.team.members.nodes | [(.[].login)]')"
|
||||
|
||||
isMember=$(echo ${members[@]} | grep -ow $GITHUB_ACTOR | wc -w)
|
||||
|
||||
if [ $isMember -eq 0 ]
|
||||
then
|
||||
echo "$GITHUB_ACTOR is not a docs team member. exiting..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Check out repo content
|
||||
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@38d90ce44d5275ad62cc48384b3d8a58c500bb5f
|
||||
with:
|
||||
node-version: 16.x
|
||||
cache: npm
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install @octokit/graphql
|
||||
|
||||
- name: Run script
|
||||
run: |
|
||||
node .github/actions-scripts/ready-for-docs-review.js
|
||||
env:
|
||||
TOKEN: ${{ secrets.DOCS_BOT_FR }}
|
||||
PROJECT_NUMBER: 2936
|
||||
ORGANIZATION: 'github'
|
||||
ITEM_NODE_ID: ${{ github.event.pull_request.node_id || github.event.issue.node_id }}
|
||||
AUTHOR_LOGIN: ${{ github.event.pull_request.user.login || github.event.issue.user.login }}
|
||||
REPO: ${{ github.repository }}
|
||||
4
.github/workflows/prod-build-deploy.yml
vendored
@@ -27,6 +27,10 @@ jobs:
|
||||
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
||||
with:
|
||||
persist-credentials: 'false'
|
||||
lfs: 'true'
|
||||
|
||||
- name: Check out LFS objects
|
||||
run: git lfs checkout
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@38d90ce44d5275ad62cc48384b3d8a58c500bb5f
|
||||
|
||||
4
.github/workflows/ready-for-doc-review.yml
vendored
@@ -33,9 +33,9 @@ jobs:
|
||||
TOKEN: ${{ secrets.DOCS_BOT_FR }}
|
||||
PROJECT_NUMBER: 2936
|
||||
ORGANIZATION: 'github'
|
||||
PR_NODE_ID: ${{ github.event.pull_request.node_id }}
|
||||
ITEM_NODE_ID: ${{ github.event.pull_request.node_id }}
|
||||
AUTHOR_LOGIN: ${{ github.event.pull_request.user.login }}
|
||||
PR_REPO: ${{ github.event.pull_request.base.repo.full_name }}
|
||||
REPO: ${{ github.event.pull_request.base.repo.full_name }}
|
||||
|
||||
# Since the projects API is still in beta, use the old workflow if something fails
|
||||
# so that we don't miss these PRs
|
||||
|
||||
30
.github/workflows/staging-deploy-pr.yml
vendored
@@ -136,12 +136,15 @@ jobs:
|
||||
target_url: ACTIONS_RUN_LOG
|
||||
})
|
||||
|
||||
- if: ${{ github.repository == 'github/docs-internal' }}
|
||||
name: Check out repo's default branch
|
||||
- name: Check out repo's default branch
|
||||
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
|
||||
with:
|
||||
# To prevent issues with cloning early access content later
|
||||
persist-credentials: 'false'
|
||||
lfs: 'true'
|
||||
|
||||
- name: Check out LFS objects
|
||||
run: git lfs checkout
|
||||
|
||||
- if: ${{ github.repository == 'github/docs-internal' }}
|
||||
name: Setup node to clone early access
|
||||
@@ -171,24 +174,25 @@ jobs:
|
||||
name: pr_build
|
||||
path: ./
|
||||
|
||||
- if: ${{ github.repository == 'github/docs-internal' }}
|
||||
name: Extract user-changes to temp directory
|
||||
- name: Extract user-changes to temp directory
|
||||
run: |
|
||||
tar -x --file=app.tar -C "$RUNNER_TEMP/"
|
||||
rm app.tar
|
||||
|
||||
# Append early access content into the temp directory
|
||||
- if: ${{ github.repository == 'github/docs-internal' }}
|
||||
name: Merge in the early access content
|
||||
# Move the LFS content into the temp directory in chunks (destructively)
|
||||
- name: Move the LFS objects
|
||||
run: |
|
||||
rsync -aiR \
|
||||
assets/images/early-access \
|
||||
content/early-access \
|
||||
data/early-access \
|
||||
"$RUNNER_TEMP/"
|
||||
git lfs ls-files --name-only | xargs -n 1 -I {} sh -c 'mkdir -p "$RUNNER_TEMP/$(dirname {})"; mv {} "$RUNNER_TEMP/$(dirname {})/"'
|
||||
|
||||
# Move the early access content into the temp directory (destructively)
|
||||
- if: ${{ github.repository == 'github/docs-internal' }}
|
||||
name: Create an updated archive
|
||||
name: Move the early access content
|
||||
run: |
|
||||
mv assets/images/early-access "$RUNNER_TEMP/assets/images/"
|
||||
mv content/early-access "$RUNNER_TEMP/content/"
|
||||
mv data/early-access "$RUNNER_TEMP/data/"
|
||||
|
||||
- name: Create an updated archive
|
||||
run: tar -c --file app.tar "$RUNNER_TEMP/"
|
||||
|
||||
# Create "app.tar.gz" and delete "app.tar"
|
||||
|
||||
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 37 KiB |
BIN
assets/images/help/codespaces/codespaces-continue-working.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 36 KiB |
BIN
assets/images/help/enterprises/emu-pat-name.png
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
assets/images/help/enterprises/emu-pat-no-expiration.png
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 43 KiB |
BIN
assets/images/help/enterprises/enterprise-pat-scope.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
assets/images/help/enterprises/okta-emu-enterprise-name.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
assets/images/help/enterprises/okta-emu-provisioning-to-app.png
Normal file
|
After Width: | Height: | Size: 92 KiB |
BIN
assets/images/help/enterprises/okta-emu-to-app-menu.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
assets/images/help/enterprises/okta-emu-token.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
assets/images/help/enterprises/okta-emu-user-role.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
assets/images/help/enterprises/saml-recovery-codes-link.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
assets/images/help/writing/display-markdown-as-source.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
@@ -37,7 +37,7 @@ export function Link(props: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<NextLink href={href || ''} locale={locale || false}>
|
||||
<NextLink href={locale ? `/${locale}${href}` : href || ''} locale={locale || false}>
|
||||
{/* eslint-disable-next-line jsx-a11y/anchor-has-content */}
|
||||
<a rel={isExternal ? 'noopener' : ''} {...restProps} />
|
||||
</NextLink>
|
||||
|
||||
@@ -171,7 +171,7 @@ export function Search({
|
||||
)}
|
||||
>
|
||||
{results.length > 0 ? (
|
||||
<ol data-testid="search-results" className="d-block mt-2">
|
||||
<ol data-testid="search-results" className="d-block mt-4">
|
||||
{results.map(({ url, breadcrumbs, heading, title, content }, index) => {
|
||||
const isActive = index === activeHit
|
||||
return (
|
||||
|
||||
126
components/VersionPicker.tsx
Normal file
@@ -0,0 +1,126 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import cx from 'classnames'
|
||||
import { Dropdown, Heading, Details, Box, Text, useDetails } from '@primer/components'
|
||||
import { ArrowRightIcon, ChevronDownIcon } from '@primer/octicons-react'
|
||||
|
||||
import { Link } from 'components/Link'
|
||||
import { useMainContext } from 'components/context/MainContext'
|
||||
import { useVersion } from 'components/hooks/useVersion'
|
||||
import { useTranslation } from 'components/hooks/useTranslation'
|
||||
|
||||
type Props = {
|
||||
hideLabel?: boolean
|
||||
variant?: 'default' | 'compact' | 'inline'
|
||||
popoverVariant?: 'inline' | 'dropdown'
|
||||
}
|
||||
export const VersionPicker = ({ variant = 'default', popoverVariant, hideLabel }: Props) => {
|
||||
const router = useRouter()
|
||||
const { currentVersion } = useVersion()
|
||||
const { allVersions, page, enterpriseServerVersions } = useMainContext()
|
||||
const { getDetailsProps, setOpen } = useDetails({ closeOnOutsideClick: true })
|
||||
const { t } = useTranslation('pages')
|
||||
|
||||
if (page.permalinks && page.permalinks.length <= 1) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{!hideLabel && (
|
||||
<Heading as="span" fontSize={1} className="d-none d-xl-inline-block mb-1">
|
||||
{t('article_version')}
|
||||
</Heading>
|
||||
)}
|
||||
<div>
|
||||
<Details
|
||||
{...getDetailsProps()}
|
||||
className={cx(
|
||||
'position-relative details-reset',
|
||||
variant === 'inline' ? 'd-block' : 'd-inline-block'
|
||||
)}
|
||||
data-testid="article-version-picker"
|
||||
>
|
||||
{(variant === 'compact' || variant === 'inline') && (
|
||||
<summary
|
||||
className="d-block btn btn-invisible color-text-primary"
|
||||
aria-haspopup="true"
|
||||
aria-label="Toggle version list"
|
||||
>
|
||||
{variant === 'inline' ? (
|
||||
<div className="d-flex flex-items-center flex-justify-between">
|
||||
<Text>{allVersions[currentVersion].versionTitle}</Text>
|
||||
<ChevronDownIcon size={24} className="arrow ml-md-1" />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<Text>{allVersions[currentVersion].versionTitle}</Text>
|
||||
<Dropdown.Caret />
|
||||
</>
|
||||
)}
|
||||
</summary>
|
||||
)}
|
||||
|
||||
{variant === 'default' && (
|
||||
<summary aria-haspopup="true" className="btn btn-sm">
|
||||
<Text>{allVersions[currentVersion].versionTitle}</Text>
|
||||
<Dropdown.Caret />
|
||||
</summary>
|
||||
)}
|
||||
|
||||
{popoverVariant === 'inline' ? (
|
||||
<Box py="2">
|
||||
{(page.permalinks || []).map((permalink) => {
|
||||
return (
|
||||
<Dropdown.Item key={permalink.href} onClick={() => setOpen(false)}>
|
||||
<Link href={permalink.href}>{permalink.pageVersionTitle}</Link>
|
||||
</Dropdown.Item>
|
||||
)
|
||||
})}
|
||||
<Box mt={1}>
|
||||
<Link
|
||||
onClick={() => {
|
||||
setOpen(false)
|
||||
}}
|
||||
href={`/${router.locale}/${enterpriseServerVersions[0]}/admin/all-releases`}
|
||||
className="f6 no-underline color-text-tertiary pl-3 pr-2 no-wrap"
|
||||
>
|
||||
{t('all_enterprise_releases')}{' '}
|
||||
<ArrowRightIcon verticalAlign="middle" size={15} className="mr-2" />
|
||||
</Link>
|
||||
</Box>
|
||||
</Box>
|
||||
) : (
|
||||
<Dropdown.Menu direction="sw" style={{ width: 'unset' }}>
|
||||
{(page.permalinks || []).map((permalink) => {
|
||||
return (
|
||||
<Dropdown.Item key={permalink.href} onClick={() => setOpen(false)}>
|
||||
<Link href={permalink.href}>{permalink.pageVersionTitle}</Link>
|
||||
</Dropdown.Item>
|
||||
)
|
||||
})}
|
||||
<Box
|
||||
borderColor="border.default"
|
||||
borderTopWidth={1}
|
||||
borderTopStyle="solid"
|
||||
mt={2}
|
||||
pt={2}
|
||||
pb={1}
|
||||
>
|
||||
<Link
|
||||
onClick={() => {
|
||||
setOpen(false)
|
||||
}}
|
||||
href={`/${router.locale}/${enterpriseServerVersions[0]}/admin/all-releases`}
|
||||
className="f6 no-underline color-text-tertiary pl-3 pr-2 no-wrap"
|
||||
>
|
||||
{t('all_enterprise_releases')}{' '}
|
||||
<ArrowRightIcon verticalAlign="middle" size={15} className="mr-2" />
|
||||
</Link>
|
||||
</Box>
|
||||
</Dropdown.Menu>
|
||||
)}
|
||||
</Details>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
@import "@primer/css/layout/index.scss";
|
||||
@import "@primer/css/support/variables/layout.scss";
|
||||
@import "@primer/css/marketing/support/variables.scss";
|
||||
|
||||
.container {
|
||||
max-width: 720px;
|
||||
|
||||
@include breakpoint(xl) {
|
||||
max-width: none;
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr;
|
||||
grid-template-columns: minmax(500px, 720px) minmax(220px, 1fr);
|
||||
grid-template-areas:
|
||||
"top right-sidebar"
|
||||
"bottom right-sidebar";
|
||||
column-gap: $spacer-6;
|
||||
}
|
||||
|
||||
@include breakpoint(xl) {
|
||||
column-gap: $spacer-9;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
grid-area: right-sidebar;
|
||||
}
|
||||
|
||||
.sidebarContent {
|
||||
@include breakpoint(xl) {
|
||||
position: sticky;
|
||||
top: $spacer-4;
|
||||
max-height: calc(100vh - #{$spacer-4});
|
||||
overflow-y: auto;
|
||||
padding-bottom: $spacer-4;
|
||||
}
|
||||
}
|
||||
|
||||
.head {
|
||||
grid-area: top;
|
||||
}
|
||||
|
||||
.content {
|
||||
grid-area: bottom;
|
||||
}
|
||||
@@ -1,30 +1,78 @@
|
||||
import React from 'react'
|
||||
import cx from 'classnames'
|
||||
import styles from './ArticleGridLayout.module.scss'
|
||||
import styled from 'styled-components'
|
||||
import { Box, themeGet } from '@primer/components'
|
||||
|
||||
type Props = {
|
||||
head?: React.ReactNode
|
||||
intro?: React.ReactNode
|
||||
topperSidebar?: React.ReactNode
|
||||
topper?: React.ReactNode
|
||||
toc?: React.ReactNode
|
||||
children?: React.ReactNode
|
||||
className?: string
|
||||
}
|
||||
export const ArticleGridLayout = ({ head, toc, children, className }: Props) => {
|
||||
export const ArticleGridLayout = ({
|
||||
intro,
|
||||
topperSidebar,
|
||||
topper,
|
||||
toc,
|
||||
children,
|
||||
className,
|
||||
}: Props) => {
|
||||
return (
|
||||
<div className={cx(styles.container, className)}>
|
||||
{/* head */}
|
||||
{head && <div className={styles.head}>{head}</div>}
|
||||
|
||||
{/* toc */}
|
||||
<Container className={className}>
|
||||
{topper && <Box gridArea="topper">{topper}</Box>}
|
||||
{topperSidebar && <Box gridArea="topper-sidebar">{topperSidebar}</Box>}
|
||||
{toc && (
|
||||
<div className={cx(styles.sidebar, 'border-bottom border-xl-0 pb-4 mb-5 pb-xl-0 mb-xl-0')}>
|
||||
<div className={styles.sidebarContent}>{toc}</div>
|
||||
</div>
|
||||
<SidebarContent
|
||||
gridArea="sidebar"
|
||||
alignSelf="flex-start"
|
||||
className="border-bottom border-xl-0 pb-4 mb-5 pb-xl-0 mb-xl-0"
|
||||
>
|
||||
{toc}
|
||||
</SidebarContent>
|
||||
)}
|
||||
|
||||
{/* content */}
|
||||
<div data-search="article-body" className={styles.content}>
|
||||
{intro && <Box gridArea="intro">{intro}</Box>}
|
||||
|
||||
<Box gridArea="content" data-search="article-body">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
const Container = styled(Box)`
|
||||
max-width: 720px;
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
'topper'
|
||||
'topper-sidebar'
|
||||
'intro'
|
||||
'sidebar'
|
||||
'content';
|
||||
|
||||
row-gap: ${themeGet('space.2')};
|
||||
|
||||
@media (min-width: ${themeGet('breakpoints.3')}) {
|
||||
max-width: none;
|
||||
grid-template-rows: auto 1fr;
|
||||
grid-template-columns: minmax(500px, 720px) minmax(220px, 1fr);
|
||||
grid-template-areas:
|
||||
'topper topper-sidebar'
|
||||
'intro sidebar'
|
||||
'content sidebar';
|
||||
column-gap: ${themeGet('space.9')};
|
||||
row-gap: 0;
|
||||
}
|
||||
`
|
||||
|
||||
const SidebarContent = styled(Box)`
|
||||
@media (min-width: ${themeGet('breakpoints.3')}) {
|
||||
position: sticky;
|
||||
padding-top: ${themeGet('space.4')};
|
||||
top: 0;
|
||||
max-height: calc(100vh - ${themeGet('space.4')});
|
||||
overflow-y: auto;
|
||||
padding-bottom: ${themeGet('space.4')};
|
||||
}
|
||||
`
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import cx from 'classnames'
|
||||
import { Heading } from '@primer/components'
|
||||
|
||||
import { ZapIcon, InfoIcon } from '@primer/octicons-react'
|
||||
import { Callout } from 'components/ui/Callout'
|
||||
|
||||
import { Link } from 'components/Link'
|
||||
import { DefaultLayout } from 'components/DefaultLayout'
|
||||
import { ArticleTopper } from 'components/article/ArticleTopper'
|
||||
import { ArticleTitle } from 'components/article/ArticleTitle'
|
||||
import { useArticleContext } from 'components/context/ArticleContext'
|
||||
import { useTranslation } from 'components/hooks/useTranslation'
|
||||
@@ -14,6 +14,8 @@ import { LearningTrackNav } from './LearningTrackNav'
|
||||
import { MarkdownContent } from 'components/ui/MarkdownContent'
|
||||
import { Lead } from 'components/ui/Lead'
|
||||
import { ArticleGridLayout } from './ArticleGridLayout'
|
||||
import { VersionPicker } from 'components/VersionPicker'
|
||||
import { Breadcrumbs } from 'components/Breadcrumbs'
|
||||
|
||||
// Mapping of a "normal" article to it's interactive counterpart
|
||||
const interactiveAlternatives: Record<string, { href: string }> = {
|
||||
@@ -44,12 +46,11 @@ export const ArticlePage = () => {
|
||||
|
||||
return (
|
||||
<DefaultLayout>
|
||||
<div className="container-xl px-3 px-md-6 my-4 my-lg-4">
|
||||
<ArticleTopper />
|
||||
|
||||
<div className="container-xl px-3 px-md-6 my-4">
|
||||
<ArticleGridLayout
|
||||
className="mt-7"
|
||||
head={
|
||||
topper={<Breadcrumbs />}
|
||||
topperSidebar={<VersionPicker />}
|
||||
intro={
|
||||
<>
|
||||
<ArticleTitle>{title}</ArticleTitle>
|
||||
|
||||
@@ -124,11 +125,11 @@ export const ArticlePage = () => {
|
||||
)}
|
||||
{miniTocItems.length > 1 && (
|
||||
<>
|
||||
<h2 id="in-this-article" className="f5 mb-2">
|
||||
<Heading as="h2" fontSize={1} id="in-this-article" className="mb-1">
|
||||
<a className="Link--primary" href="#in-this-article">
|
||||
{t('miniToc')}
|
||||
</a>
|
||||
</h2>
|
||||
</Heading>
|
||||
<ul className="list-style-none pl-0 f5 mb-0">
|
||||
{miniTocItems.map((item) => {
|
||||
return (
|
||||
|
||||
@@ -4,7 +4,7 @@ type Props = {
|
||||
export const ArticleTitle = ({ children }: Props) => {
|
||||
return (
|
||||
<div className="d-flex flex-items-baseline flex-justify-between">
|
||||
<h1 className="my-4 border-bottom-0">{children}</h1>
|
||||
<h1 className="mt-4 border-bottom-0">{children}</h1>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import { Breadcrumbs } from 'components/Breadcrumbs'
|
||||
import { ArticleVersionPicker } from 'components/article/ArticleVersionPicker'
|
||||
|
||||
export const ArticleTopper = () => {
|
||||
return (
|
||||
<div className="d-lg-flex flex-justify-between">
|
||||
<div className="d-block d-lg-none mb-2">
|
||||
<ArticleVersionPicker />
|
||||
</div>
|
||||
<div className="d-flex flex-items-center">
|
||||
<Breadcrumbs />
|
||||
</div>
|
||||
<div className="d-none d-lg-block">
|
||||
<ArticleVersionPicker />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import { Dropdown } from '@primer/components'
|
||||
|
||||
import { Link } from 'components/Link'
|
||||
import { useMainContext } from 'components/context/MainContext'
|
||||
import { useVersion } from 'components/hooks/useVersion'
|
||||
import { useTranslation } from 'components/hooks/useTranslation'
|
||||
|
||||
export const ArticleVersionPicker = () => {
|
||||
const router = useRouter()
|
||||
const { currentVersion } = useVersion()
|
||||
const { allVersions, page, enterpriseServerVersions } = useMainContext()
|
||||
const { t } = useTranslation('pages')
|
||||
|
||||
if (page.permalinks && page.permalinks.length <= 1) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
css={`
|
||||
ul {
|
||||
width: unset;
|
||||
}
|
||||
`}
|
||||
data-testid="article-version-picker"
|
||||
>
|
||||
<summary className="btn btn-outline p-2 outline-none">
|
||||
<span className="d-md-none d-xl-inline-block">{t('article_version')}</span>{' '}
|
||||
{allVersions[currentVersion].versionTitle}
|
||||
<Dropdown.Caret />
|
||||
</summary>
|
||||
<Dropdown.Menu direction="sw">
|
||||
{(page.permalinks || []).map((permalink) => {
|
||||
return (
|
||||
<Dropdown.Item key={permalink.href}>
|
||||
<Link href={permalink.href}>{permalink.pageVersionTitle}</Link>
|
||||
</Dropdown.Item>
|
||||
)
|
||||
})}
|
||||
<div className="pb-1">
|
||||
<Link
|
||||
href={`/${router.locale}/${enterpriseServerVersions[0]}/admin/all-releases`}
|
||||
className="f6 no-underline color-text-tertiary pl-3 pr-2 no-wrap"
|
||||
>
|
||||
See all Enterprise releases
|
||||
</Link>
|
||||
</div>
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
)
|
||||
}
|
||||
@@ -6,7 +6,7 @@ type Props = {
|
||||
}
|
||||
export function LearningTrackNav({ track }: Props) {
|
||||
const { t } = useTranslation('learning_track_nav')
|
||||
const { prevGuide, nextGuide, trackName } = track
|
||||
const { prevGuide, nextGuide, trackName, trackProduct } = track
|
||||
return (
|
||||
<div
|
||||
data-testid="learning-track-nav"
|
||||
@@ -17,7 +17,7 @@ export function LearningTrackNav({ track }: Props) {
|
||||
<>
|
||||
<span className="f6 color-text-secondary">{t('prevGuide')}</span>
|
||||
<a
|
||||
href={`${prevGuide.href}?learn=${trackName}`}
|
||||
href={`${prevGuide.href}?learn=${trackName}&learnProduct=${trackProduct}`}
|
||||
className="text-bold color-text-secondary"
|
||||
>
|
||||
{prevGuide.title}
|
||||
@@ -31,7 +31,7 @@ export function LearningTrackNav({ track }: Props) {
|
||||
<>
|
||||
<span className="f6 color-text-secondary">{t('nextGuide')}</span>
|
||||
<a
|
||||
href={`${nextGuide.href}?learn=${trackName}`}
|
||||
href={`${nextGuide.href}?learn=${trackName}&learnProduct=${trackProduct}`}
|
||||
className="text-bold color-text-secondary text-right f4"
|
||||
>
|
||||
{nextGuide.title}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createContext, useContext } from 'react'
|
||||
|
||||
export type LearningTrack = {
|
||||
trackName?: string
|
||||
trackProduct?: string
|
||||
prevGuide?: { href: string; title: string }
|
||||
nextGuide?: { href: string; title: string }
|
||||
}
|
||||
|
||||
@@ -62,10 +62,6 @@ export type MainContextT = {
|
||||
article?: BreadcrumbT
|
||||
}
|
||||
activeProducts: Array<ProductT>
|
||||
community_redirect: {
|
||||
name: string
|
||||
href: string
|
||||
}
|
||||
currentProduct?: ProductT
|
||||
currentLayoutName: string
|
||||
isHomepageVersion: boolean
|
||||
@@ -114,7 +110,6 @@ export const getMainContext = (req: any, res: any): MainContextT => {
|
||||
return {
|
||||
breadcrumbs: req.context.breadcrumbs || {},
|
||||
activeProducts: req.context.activeProducts,
|
||||
community_redirect: req.context.page?.community_redirect || {},
|
||||
currentProduct: req.context.productMap[req.context.currentProduct] || null,
|
||||
currentLayoutName: req.context.currentLayoutName,
|
||||
isHomepageVersion: req.context.page?.documentType === 'homepage',
|
||||
|
||||
@@ -3,6 +3,7 @@ import pick from 'lodash/pick'
|
||||
|
||||
export type FeaturedTrack = {
|
||||
trackName: string
|
||||
trackProduct: string
|
||||
title: string
|
||||
description: string
|
||||
guides?: Array<{ href: string; page?: { type: string }; title: string; intro: string }>
|
||||
@@ -47,14 +48,14 @@ export const getProductSubLandingContextFromRequest = (req: any): ProductSubLand
|
||||
title: req.context.productMap[req.context.currentProduct].name,
|
||||
featuredTrack: page.featuredTrack
|
||||
? {
|
||||
...pick(page.featuredTrack, ['title', 'description', 'trackName']),
|
||||
...pick(page.featuredTrack, ['title', 'description', 'trackName', 'trackProduct']),
|
||||
guides: (page.featuredTrack?.guides || []).map((guide: any) => {
|
||||
return pick(guide, ['title', 'intro', 'href', 'page.type'])
|
||||
}),
|
||||
}
|
||||
: null,
|
||||
learningTracks: (page.learningTracks || []).map((track: any) => ({
|
||||
...pick(track, ['title', 'description', 'trackName']),
|
||||
...pick(track, ['title', 'description', 'trackName', 'trackProduct']),
|
||||
guides: (track.guides || []).map((guide: any) => {
|
||||
return pick(guide, ['title', 'intro', 'href', 'page.type'])
|
||||
}),
|
||||
|
||||
@@ -38,7 +38,6 @@ export const useTocLandingContext = (): TocLandingContextT => {
|
||||
}
|
||||
|
||||
export const getTocLandingContextFromRequest = (req: any): TocLandingContextT => {
|
||||
const isEarlyAccess = req.context.page?.documentType === 'early-access'
|
||||
return {
|
||||
title: req.context.page.titlePlainText,
|
||||
productCallout: req.context.page.product || '',
|
||||
@@ -49,7 +48,7 @@ export const getTocLandingContextFromRequest = (req: any): TocLandingContextT =>
|
||||
variant: req.context.genericTocFlat ? 'expanded' : 'compact',
|
||||
|
||||
featuredLinks: getFeaturedLinksFromReq(req),
|
||||
renderedPage: isEarlyAccess ? req.context.renderedPage : '',
|
||||
renderedPage: req.context.renderedPage,
|
||||
currentLearningTrack: req.context.currentLearningTrack,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
import cx from 'classnames'
|
||||
import { useRouter } from 'next/router'
|
||||
import { Dropdown, Details, useDetails } from '@primer/components'
|
||||
import { ChevronDownIcon } from '@primer/octicons-react'
|
||||
|
||||
import { Link } from 'components/Link'
|
||||
import { useMainContext } from 'components/context/MainContext'
|
||||
import { useVersion } from 'components/hooks/useVersion'
|
||||
|
||||
type Props = {
|
||||
variant?: 'inline'
|
||||
}
|
||||
export const HomepageVersionPicker = ({ variant }: Props) => {
|
||||
const router = useRouter()
|
||||
const { currentVersion } = useVersion()
|
||||
const { getDetailsProps } = useDetails({})
|
||||
const { allVersions, page, enterpriseServerVersions } = useMainContext()
|
||||
|
||||
if (page.permalinks && page.permalinks.length <= 1) {
|
||||
return null
|
||||
}
|
||||
|
||||
const label = allVersions[currentVersion].versionTitle
|
||||
|
||||
if (variant === 'inline') {
|
||||
return (
|
||||
<Details {...getDetailsProps()} className="details-reset">
|
||||
<summary className="outline-none" aria-label="Toggle language list">
|
||||
<div className="d-flex flex-items-center flex-justify-between py-2">
|
||||
<span>{label}</span>
|
||||
<ChevronDownIcon size={24} className="arrow ml-md-1" />
|
||||
</div>
|
||||
</summary>
|
||||
<div>
|
||||
{(page.permalinks || []).map((permalink) => {
|
||||
return (
|
||||
<Link
|
||||
key={permalink.href}
|
||||
href={permalink.href}
|
||||
className={cx(
|
||||
'd-block py-2',
|
||||
permalink.href === router.asPath
|
||||
? 'color-text-link text-underline active'
|
||||
: 'Link--primary no-underline'
|
||||
)}
|
||||
>
|
||||
{permalink.pageVersionTitle}
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
<Link
|
||||
href={`/${router.locale}/${enterpriseServerVersions[0]}/admin/all-releases`}
|
||||
className="f6 no-underline color-text-tertiary no-wrap"
|
||||
>
|
||||
See all Enterprise releases
|
||||
</Link>
|
||||
</div>
|
||||
</Details>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
css={`
|
||||
ul {
|
||||
width: unset;
|
||||
}
|
||||
`}
|
||||
>
|
||||
<summary>
|
||||
{label}
|
||||
<Dropdown.Caret />
|
||||
</summary>
|
||||
<Dropdown.Menu direction="sw">
|
||||
{(page.permalinks || []).map((permalink) => {
|
||||
return (
|
||||
<Dropdown.Item key={permalink.href}>
|
||||
<Link href={permalink.href}>{permalink.pageVersionTitle}</Link>
|
||||
</Dropdown.Item>
|
||||
)
|
||||
})}
|
||||
<div className="pb-1">
|
||||
<Link
|
||||
href={`/${router.locale}/${enterpriseServerVersions[0]}/admin/all-releases`}
|
||||
className="f6 no-underline color-text-tertiary pl-3 pr-2 no-wrap"
|
||||
>
|
||||
See all Enterprise releases
|
||||
</Link>
|
||||
</div>
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
)
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
import { DefaultLayout } from 'components/DefaultLayout'
|
||||
import { TableOfContents } from 'components/landing/TableOfContents'
|
||||
import { useTocLandingContext } from 'components/context/TocLandingContext'
|
||||
import { ArticleTopper } from 'components/article/ArticleTopper'
|
||||
import { VersionPicker } from 'components/VersionPicker'
|
||||
import { Breadcrumbs } from 'components/Breadcrumbs'
|
||||
import { ArticleTitle } from 'components/article/ArticleTitle'
|
||||
import { MarkdownContent } from 'components/ui/MarkdownContent'
|
||||
import { ArticleList } from 'components/landing/ArticleList'
|
||||
@@ -9,7 +10,7 @@ import { useTranslation } from 'components/hooks/useTranslation'
|
||||
import { ArticleGridLayout } from 'components/article/ArticleGridLayout'
|
||||
import { Callout } from 'components/ui/Callout'
|
||||
import { Lead } from 'components/ui/Lead'
|
||||
import { LearningTrackNav } from '../article/LearningTrackNav'
|
||||
import { LearningTrackNav } from 'components/article/LearningTrackNav'
|
||||
|
||||
export const TocLanding = () => {
|
||||
const {
|
||||
@@ -26,10 +27,8 @@ export const TocLanding = () => {
|
||||
|
||||
return (
|
||||
<DefaultLayout>
|
||||
<div className="container-xl px-3 px-md-6 my-4 my-lg-4">
|
||||
<ArticleTopper />
|
||||
|
||||
<ArticleGridLayout className="mt-7">
|
||||
<div className="container-xl px-3 px-md-6 my-4">
|
||||
<ArticleGridLayout topper={<Breadcrumbs />} topperSidebar={<VersionPicker />}>
|
||||
<ArticleTitle>{title}</ArticleTitle>
|
||||
|
||||
{introPlainText && <Lead>{introPlainText}</Lead>}
|
||||
@@ -59,7 +58,7 @@ export const TocLanding = () => {
|
||||
)}
|
||||
|
||||
{renderedPage && (
|
||||
<div id="article-contents">
|
||||
<div id="article-contents" className="mb-5">
|
||||
<MarkdownContent>{renderedPage}</MarkdownContent>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -7,18 +7,29 @@ import { useMainContext } from 'components/context/MainContext'
|
||||
export const Support = () => {
|
||||
const { isEnterprise } = useVersion()
|
||||
const { t } = useTranslation('support')
|
||||
const { community_redirect } = useMainContext()
|
||||
const { relativePath } = useMainContext()
|
||||
|
||||
let updatedCommunityLink = ''
|
||||
|
||||
if (
|
||||
relativePath?.startsWith('codespaces') ||
|
||||
relativePath?.startsWith('discussions') ||
|
||||
relativePath?.startsWith('sponsors')
|
||||
) {
|
||||
const product = relativePath.substring(0, relativePath.indexOf('/'))
|
||||
updatedCommunityLink = `https://github.com/github/feedback/discussions/categories/${product}-feedback`
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3 className="mb-2 f4">{t`still_need_help`}</h3>
|
||||
<a
|
||||
id="ask-community"
|
||||
href={community_redirect.href || 'https://github.community/'}
|
||||
href={updatedCommunityLink === '' ? 'https://github.community/' : updatedCommunityLink}
|
||||
className="btn btn-outline mr-4 mt-2"
|
||||
>
|
||||
<PeopleIcon size="small" className="octicon mr-1" />
|
||||
{Object.keys(community_redirect).length === 0 ? t`ask_community` : community_redirect.name}
|
||||
{updatedCommunityLink === '' ? t`ask_community` : 'Provide GitHub Feedback'}
|
||||
</a>
|
||||
<a
|
||||
id="contact-us"
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useState } from 'react'
|
||||
import cx from 'classnames'
|
||||
import { useRouter } from 'next/router'
|
||||
import { MarkGithubIcon, ThreeBarsIcon, XIcon } from '@primer/octicons-react'
|
||||
import { ButtonOutline } from '@primer/components'
|
||||
|
||||
import { Link } from 'components/Link'
|
||||
import { useMainContext } from 'components/context/MainContext'
|
||||
@@ -10,8 +9,8 @@ import { LanguagePicker } from './LanguagePicker'
|
||||
import { HeaderNotifications } from 'components/page-header/HeaderNotifications'
|
||||
import { ProductPicker } from 'components/page-header/ProductPicker'
|
||||
import { useTranslation } from 'components/hooks/useTranslation'
|
||||
import { HomepageVersionPicker } from 'components/landing/HomepageVersionPicker'
|
||||
import { Search } from 'components/Search'
|
||||
import { VersionPicker } from 'components/VersionPicker'
|
||||
|
||||
export const Header = () => {
|
||||
const router = useRouter()
|
||||
@@ -31,25 +30,23 @@ export const Header = () => {
|
||||
<div className="border-bottom color-border-secondary no-print">
|
||||
{error !== '404' && <HeaderNotifications />}
|
||||
|
||||
<header
|
||||
className="container-xl px-3 px-md-6 pt-3 pb-3 position-relative"
|
||||
style={{ zIndex: 2 }}
|
||||
>
|
||||
<header className={cx('container-xl px-3 px-md-6 pt-3 pb-3 position-relative z-3')}>
|
||||
{/* desktop header */}
|
||||
<div className="d-none d-lg-flex flex-justify-end" data-testid="desktop-header">
|
||||
<div
|
||||
className="d-none d-lg-flex flex-justify-end flex-items-center"
|
||||
data-testid="desktop-header"
|
||||
>
|
||||
{showVersionPicker && (
|
||||
<div className="py-2 mr-4">
|
||||
<HomepageVersionPicker />
|
||||
<div className="mr-2">
|
||||
<VersionPicker hideLabel={true} variant="compact" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="py-2">
|
||||
<LanguagePicker />
|
||||
</div>
|
||||
|
||||
{/* <!-- GitHub.com homepage and 404 page has a stylized search; Enterprise homepages do not --> */}
|
||||
{relativePath !== 'index.md' && error !== '404' && (
|
||||
<div className="d-inline-block ml-4">
|
||||
<div className="d-inline-block ml-3">
|
||||
<Search updateSearchParams={updateSearchParams} isOverlay={true} />
|
||||
</div>
|
||||
)}
|
||||
@@ -72,14 +69,14 @@ export const Header = () => {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<ButtonOutline
|
||||
<button
|
||||
className="btn"
|
||||
data-testid="mobile-menu-button"
|
||||
css
|
||||
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
||||
aria-label="Navigation Menu"
|
||||
>
|
||||
{isMenuOpen ? <XIcon size="small" /> : <ThreeBarsIcon size="small" />}
|
||||
</ButtonOutline>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -87,31 +84,33 @@ export const Header = () => {
|
||||
<div className="relative">
|
||||
<div
|
||||
className={cx(
|
||||
'width-full position-absolute left-0 right-0 color-shadow-large color-bg-primary px-3 px-md-6 pb-3',
|
||||
'width-full position-absolute left-0 right-0 color-shadow-large color-bg-primary px-2 px-md-4 pb-3',
|
||||
isMenuOpen ? 'd-block' : 'd-none'
|
||||
)}
|
||||
>
|
||||
<div className="mt-3 mb-2">
|
||||
<h4 className="f5 text-normal color-text-secondary">{t('explore_by_product')}</h4>
|
||||
<h4 className="f5 text-normal color-text-secondary ml-3">
|
||||
{t('explore_by_product')}
|
||||
</h4>
|
||||
|
||||
<ProductPicker />
|
||||
</div>
|
||||
|
||||
{/* <!-- Versions picker that only appears in the header on landing pages --> */}
|
||||
{showVersionPicker && (
|
||||
<div className="border-top py-2">
|
||||
<HomepageVersionPicker variant="inline" />
|
||||
</div>
|
||||
<>
|
||||
<div className="border-top my-2 mx-3" />
|
||||
<VersionPicker hideLabel={true} variant="inline" popoverVariant={'inline'} />
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* <!-- Language picker - 'English', 'Japanese', etc --> */}
|
||||
<div className="border-top py-2">
|
||||
<div className="border-top my-2 mx-3" />
|
||||
<LanguagePicker variant="inline" />
|
||||
</div>
|
||||
|
||||
{/* <!-- GitHub.com homepage and 404 page has a stylized search; Enterprise homepages do not --> */}
|
||||
{relativePath !== 'index.md' && error !== '404' && (
|
||||
<div className="pt-3 border-top">
|
||||
<div className="my-2 pt-3 mx-3">
|
||||
<Search updateSearchParams={updateSearchParams} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import cx from 'classnames'
|
||||
import { useRouter } from 'next/router'
|
||||
import { Dropdown, Details, useDetails } from '@primer/components'
|
||||
import { Box, Dropdown, Details, Text, useDetails } from '@primer/components'
|
||||
import { ChevronDownIcon } from '@primer/octicons-react'
|
||||
|
||||
import { Link } from 'components/Link'
|
||||
@@ -12,39 +11,32 @@ type Props = {
|
||||
export const LanguagePicker = ({ variant }: Props) => {
|
||||
const router = useRouter()
|
||||
const { languages } = useLanguages()
|
||||
const { getDetailsProps } = useDetails({})
|
||||
const { getDetailsProps, setOpen } = useDetails({ closeOnOutsideClick: true })
|
||||
const locale = router.locale || 'en'
|
||||
const langs = Object.values(languages)
|
||||
const selectedLang = languages[locale]
|
||||
|
||||
if (variant === 'inline') {
|
||||
return (
|
||||
<Details {...getDetailsProps()} className="details-reset">
|
||||
<summary className="outline-none" aria-label="Toggle language list">
|
||||
<div className="d-flex flex-items-center flex-justify-between py-2">
|
||||
<span>{selectedLang.nativeName || selectedLang.name}</span>
|
||||
<Details {...getDetailsProps()} data-testid="language-picker">
|
||||
<summary
|
||||
className="d-block btn btn-invisible color-text-primary"
|
||||
aria-label="Toggle language list"
|
||||
>
|
||||
<div className="d-flex flex-items-center flex-justify-between">
|
||||
<Text>{selectedLang.nativeName || selectedLang.name}</Text>
|
||||
<ChevronDownIcon size={24} className="arrow ml-md-1" />
|
||||
</div>
|
||||
</summary>
|
||||
<div>
|
||||
<Box mt={1}>
|
||||
{langs.map((lang) => {
|
||||
if (lang.wip) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Link
|
||||
key={lang.code}
|
||||
href={router.asPath}
|
||||
locale={lang.code}
|
||||
disableClientTransition={true}
|
||||
className={cx(
|
||||
'd-block py-2',
|
||||
lang.code === router.locale
|
||||
? 'color-text-link text-underline active'
|
||||
: 'Link--primary no-underline'
|
||||
)}
|
||||
>
|
||||
<Dropdown.Item onClick={() => setOpen(false)} key={lang.code}>
|
||||
<Link href={router.asPath} locale={lang.code}>
|
||||
{lang.nativeName ? (
|
||||
<>
|
||||
{lang.nativeName} ({lang.name})
|
||||
@@ -53,35 +45,29 @@ export const LanguagePicker = ({ variant }: Props) => {
|
||||
lang.name
|
||||
)}
|
||||
</Link>
|
||||
</Dropdown.Item>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</Box>
|
||||
</Details>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
css={`
|
||||
ul {
|
||||
width: unset;
|
||||
}
|
||||
`}
|
||||
data-testid="language-picker"
|
||||
>
|
||||
<summary>
|
||||
{selectedLang.nativeName || selectedLang.name}
|
||||
<Details {...getDetailsProps()} data-testid="language-picker" className="position-relative">
|
||||
<summary className="d-block btn btn-invisible color-text-primary">
|
||||
<Text>{selectedLang.nativeName || selectedLang.name}</Text>
|
||||
<Dropdown.Caret />
|
||||
</summary>
|
||||
<Dropdown.Menu direction="sw">
|
||||
<Dropdown.Menu direction="sw" style={{ width: 'unset' }}>
|
||||
{langs.map((lang) => {
|
||||
if (lang.wip) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Dropdown.Item key={lang.code}>
|
||||
<Link href={router.asPath} locale={lang.code} disableClientTransition={true}>
|
||||
<Dropdown.Item key={lang.code} onClick={() => setOpen(false)}>
|
||||
<Link href={router.asPath} locale={lang.code}>
|
||||
{lang.nativeName ? (
|
||||
<>
|
||||
{lang.nativeName} ({lang.name})
|
||||
@@ -94,6 +80,6 @@ export const LanguagePicker = ({ variant }: Props) => {
|
||||
)
|
||||
})}
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
</Details>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,43 +1,37 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import cx from 'classnames'
|
||||
|
||||
import { Link } from 'components/Link'
|
||||
import { useMainContext } from 'components/context/MainContext'
|
||||
import { ChevronDownIcon, LinkExternalIcon } from '@primer/octicons-react'
|
||||
import { Details, useDetails } from '@primer/components'
|
||||
import { Box, Dropdown, Details, useDetails } from '@primer/components'
|
||||
|
||||
// Product Picker - GitHub.com, Enterprise Server, etc
|
||||
export const ProductPicker = () => {
|
||||
const router = useRouter()
|
||||
const { activeProducts, currentProduct } = useMainContext()
|
||||
const { getDetailsProps } = useDetails({})
|
||||
const { getDetailsProps, setOpen } = useDetails({ closeOnOutsideClick: true })
|
||||
|
||||
return (
|
||||
<Details {...getDetailsProps()} className="details-reset">
|
||||
<summary
|
||||
className="color-text-link outline-none"
|
||||
className="d-block color-text-primary btn btn-invisible"
|
||||
role="button"
|
||||
aria-label="Toggle products list"
|
||||
>
|
||||
<div id="current-product" className="d-flex flex-items-center flex-justify-between py-2">
|
||||
{/* <!-- Product switcher - GitHub.com, Enterprise Server, etc -->
|
||||
<!-- 404 and 500 error layouts are not real pages so we need to hardcode the name for those --> */}
|
||||
<div
|
||||
data-testid="current-product"
|
||||
data-current-product-path={currentProduct?.href}
|
||||
className="d-flex flex-items-center flex-justify-between"
|
||||
>
|
||||
<span>{currentProduct?.name || 'All Products'}</span>
|
||||
<ChevronDownIcon size={24} className="arrow ml-md-1" />
|
||||
</div>
|
||||
</summary>
|
||||
<div id="homepages" style={{ zIndex: 6 }}>
|
||||
<Box data-testid="product-picker-list" py="2" style={{ zIndex: 6 }}>
|
||||
{activeProducts.map((product) => {
|
||||
return (
|
||||
<Link
|
||||
key={product.id}
|
||||
href={`${product.external ? '' : `/${router.locale}`}${product.href}`}
|
||||
className={cx(
|
||||
'd-block py-2',
|
||||
product.id === currentProduct?.id
|
||||
? 'color-text-link text-underline active'
|
||||
: 'Link--primary no-underline'
|
||||
)}
|
||||
>
|
||||
<Dropdown.Item key={product.id} onClick={() => setOpen(false)}>
|
||||
<Link href={`${product.external ? '' : `/${router.locale}`}${product.href}`}>
|
||||
{product.name}
|
||||
{product.external && (
|
||||
<span className="ml-1">
|
||||
@@ -45,9 +39,10 @@ export const ProductPicker = () => {
|
||||
</span>
|
||||
)}
|
||||
</Link>
|
||||
</Dropdown.Item>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</Box>
|
||||
</Details>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -31,17 +31,16 @@ export const CodeLanguagePicker = ({ variant }: Props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<SelectMenu css className="position-relative">
|
||||
<Button as="summary" css>
|
||||
<SelectMenu className="position-relative">
|
||||
<Button as="summary">
|
||||
{currentLanguage.label} <Dropdown.Caret />
|
||||
</Button>
|
||||
<SelectMenu.Modal css style={{ minWidth: 300 }} align="right">
|
||||
<SelectMenu.Header css>Programming Language</SelectMenu.Header>
|
||||
<SelectMenu.Modal style={{ minWidth: 300 }} align="right">
|
||||
<SelectMenu.Header>Programming Language</SelectMenu.Header>
|
||||
<SelectMenu.List>
|
||||
{codeLanguages.map((language) => (
|
||||
<SelectMenu.Item
|
||||
key={language.id}
|
||||
css
|
||||
as="a"
|
||||
href={`${routePath}?langId=${language.id}`}
|
||||
selected={language.id === currentLanguage.id}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Box, Text } from '@primer/components'
|
||||
export function LoadingIndicator() {
|
||||
return (
|
||||
<Box display="flex" flexDirection="column" alignItems="center" py={4}>
|
||||
<img width="120px" src="/playground/loading.gif" alt="bouncing octocat" />
|
||||
<img width="120px" src="/assets/images/playground/loading.gif" alt="bouncing octocat" />
|
||||
<Text fontFamily="mono" fontSize={1} color="gray.8">
|
||||
Loading...
|
||||
</Text>
|
||||
|
||||
@@ -33,7 +33,9 @@ export const LearningTrack = ({ track }: Props) => {
|
||||
<a
|
||||
className="d-inline-flex btn no-wrap mt-3 mt-md-0 flex-items-center flex-justify-center"
|
||||
role="button"
|
||||
href={`${track?.guides && track?.guides[0].href}?learn=${track?.trackName}`}
|
||||
href={`${track?.guides && track?.guides[0].href}?learn=${
|
||||
track?.trackName
|
||||
}&learnProduct=${track?.trackProduct}`}
|
||||
>
|
||||
<span>{t('start')}</span>
|
||||
<ArrowRightIcon size={20} className="ml-2" />
|
||||
@@ -44,7 +46,7 @@ export const LearningTrack = ({ track }: Props) => {
|
||||
<div key={guide.href + track?.trackName}>
|
||||
<a
|
||||
className="Box-row d-flex flex-items-center color-text-primary no-underline"
|
||||
href={`${guide.href}?learn=${track?.trackName}`}
|
||||
href={`${guide.href}?learn=${track?.trackName}&learnProduct=${track?.trackProduct}`}
|
||||
>
|
||||
<div
|
||||
className="color-bg-tertiary d-inline-flex mr-4 circle flex-items-center flex-justify-center"
|
||||
|
||||
@@ -16,7 +16,7 @@ export const SubLandingHero = () => {
|
||||
const guideItems = featuredTrack?.guides?.map((guide) => (
|
||||
<li className="px-2 d-flex flex-shrink-0" key={guide.href} style={{ width: cardWidth }}>
|
||||
<Link
|
||||
href={`${guide.href}?learn=${featuredTrack.trackName}`}
|
||||
href={`${guide.href}?learn=${featuredTrack.trackName}&learnProduct=${featuredTrack.trackProduct}`}
|
||||
className="d-inline-block Box p-5 color-bg-primary color-border-primary no-underline"
|
||||
>
|
||||
<div className="d-flex flex-justify-between flex-items-center">
|
||||
@@ -71,7 +71,7 @@ export const SubLandingHero = () => {
|
||||
<Link
|
||||
className="d-inline-flex flex-items-center flex-justify-center btn px-4 py-2 f5 no-underline text-bold"
|
||||
role="button"
|
||||
href={`${featuredTrack.guides[0].href}?learn=${featuredTrack.trackName}`}
|
||||
href={`${featuredTrack.guides[0].href}?learn=${featuredTrack.trackName}&learnProduct=${featuredTrack.trackProduct}`}
|
||||
>
|
||||
{t(`start_path`)}
|
||||
<ArrowRightIcon size={20} className="ml-2" />
|
||||
|
||||
@@ -52,6 +52,14 @@ When you sign up for an account, {% data variables.product.product_name %} provi
|
||||
|
||||
You can change the name that is displayed on your profile. This name may also be displayed next to comments you make on private repositories owned by an organization. For more information, see "[Managing the display of member names in your organization](/articles/managing-the-display-of-member-names-in-your-organization)."
|
||||
|
||||
{% ifversion fpt %}
|
||||
{% note %}
|
||||
|
||||
**Note:** If you're a member of an {% data variables.product.prodname_emu_enterprise %}, any changes to your profile name must be made through your identity provider instead of {% data variables.product.prodname_dotcom_the_website %}. {% data reusables.enterprise-accounts.emu-more-info-account %}
|
||||
|
||||
{% endnote %}
|
||||
{% endif %}
|
||||
|
||||
{% data reusables.user_settings.access_settings %}
|
||||
2. Under "Name", type the name you want to be displayed on your profile.
|
||||

|
||||
|
||||
@@ -23,6 +23,8 @@ Repositories owned by an organization can grant more granular access. For more i
|
||||
|
||||
{% ifversion fpt %}
|
||||
|
||||
If you're a member of an {% data variables.product.prodname_emu_enterprise %}, you can only invite other members of your enterprise to collaborate with you. {% data reusables.enterprise-accounts.emu-more-info-account %}
|
||||
|
||||
{% note %}
|
||||
|
||||
**Note:** {% data variables.product.company_short %} limits the number of people who can be invited to a repository within a 24-hour period. If you exceed this limit, either wait 24 hours or create an organization to collaborate with more people.
|
||||
|
||||
@@ -17,7 +17,9 @@ shortTitle: Add an email address
|
||||
|
||||
{% note %}
|
||||
|
||||
**Note**: {% data reusables.user_settings.no-verification-disposable-emails %}
|
||||
**Notes**:
|
||||
- {% data reusables.user_settings.no-verification-disposable-emails %}
|
||||
- If you're a member of an {% data variables.product.prodname_emu_enterprise %}, you cannot make changes to your email address on {% data variables.product.prodname_dotcom_the_website %}. {% data reusables.enterprise-accounts.emu-more-info-account %}
|
||||
|
||||
{% endnote %}
|
||||
|
||||
|
||||
@@ -30,6 +30,12 @@ After changing your username, your old username becomes available for anyone els
|
||||
- [@mentions](/articles/basic-writing-and-formatting-syntax/#mentioning-people-and-teams) using your old username
|
||||
- Links to [gists](/articles/creating-gists) that include your old username
|
||||
|
||||
{% ifversion fpt %}
|
||||
|
||||
If you're a member of an {% data variables.product.prodname_emu_enterprise %}, you cannot make changes to your username. {% data reusables.enterprise-accounts.emu-more-info-account %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
## Repository references
|
||||
|
||||
After you change your username, {% data variables.product.product_name %} will automatically redirect references to your repositories.
|
||||
|
||||
@@ -14,7 +14,15 @@ shortTitle: Manage theme settings
|
||||
|
||||
For choice and flexibility in how and when you use {% data variables.product.product_name %}, you can configure theme settings to change how {% data variables.product.product_name %} looks to you. You can choose from themes that are light or dark, or you can configure {% data variables.product.product_name %} to follow your system settings.
|
||||
|
||||
You may want to use a dark theme to reduce power consumption on certain devices, to reduce eye strain in low-light conditions, or because you prefer how the theme looks.{% ifversion fpt or ghae-issue-4618 %} People with visual impairment may benefit from the dark high contrast theme, with greater contrast between foreground and background elements.{% endif %}
|
||||
You may want to use a dark theme to reduce power consumption on certain devices, to reduce eye strain in low-light conditions, or because you prefer how the theme looks.
|
||||
|
||||
{% ifversion fpt or ghae-issue-4618 %} If you have low vision, you may benefit from a high contrast theme, with greater contrast between foreground and background elements.{% endif %}{% ifversion fpt or ghae-issue-4619 %} If you have colorblindness, you may benefit from our light and dark colorblind themes.
|
||||
|
||||
{% note %}
|
||||
|
||||
**Note:** The colorblind themes are currently in public beta. For more information on enabling features in public beta, see "[Exploring early access releases with feature preview](/get-started/using-github/exploring-early-access-releases-with-feature-preview)."
|
||||
|
||||
{% endnote %}{% endif %}
|
||||
|
||||
{% data reusables.user_settings.access_settings %}
|
||||
1. In the user settings sidebar, click **Appearance**.
|
||||
@@ -26,6 +34,8 @@ You may want to use a dark theme to reduce power consumption on certain devices,
|
||||
{% ifversion fpt or ghae-issue-4618 %}{% else %}{% endif %}
|
||||
- If you chose to follow your system settings, click a day theme and a night theme.
|
||||
{% ifversion fpt or ghae-issue-4618 %}{% else %}{% endif %}
|
||||
{% ifversion fpt or ghae-issue-4619 %}
|
||||
- If you would like to choose a theme which is currently in public beta, you will first need to enable it with feature preview. For more information, see "[Exploring early access releases with feature preview](/get-started/using-github/exploring-early-access-releases-with-feature-preview)."{% endif %}
|
||||
|
||||
## Further reading
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@ The `github` context contains information about the workflow run and the event t
|
||||
| `github.repository_owner` | `string` | The repository owner's name. For example, `Codertocat`. |
|
||||
| `github.run_id` | `string` | {% data reusables.github-actions.run_id_description %} |
|
||||
| `github.run_number` | `string` | {% data reusables.github-actions.run_number_description %} |
|
||||
| `github.run_attempt` | `string` | A unique number for each attempt of a particular workflow run in a repository. This number begins at 1 for the workflow run's first attempt, and increments with each re-run. |
|
||||
| `github.server_url` | `string` | Returns the URL of the GitHub server. For example: `https://github.com`. |
|
||||
| `github.sha` | `string` | The commit SHA that triggered the workflow run. |
|
||||
| `github.token` | `string` | A token to authenticate on behalf of the GitHub App installed on your repository. This is functionally equivalent to the `GITHUB_TOKEN` secret. For more information, see "[Authenticating with the GITHUB_TOKEN](/actions/automating-your-workflow-with-github-actions/authenticating-with-the-github_token)." |
|
||||
|
||||
@@ -84,7 +84,7 @@ The following table shows which toolkit functions are available within a workflo
|
||||
| `core.setOutput` | `set-output` |
|
||||
| `core.setSecret` | `add-mask` |
|
||||
| `core.startGroup` | `group` |
|
||||
| `core.warning` | `warning file` |
|
||||
| `core.warning` | `warning` |
|
||||
|
||||
{% ifversion ghes < 3.0 %}
|
||||
## Setting an environment variable
|
||||
|
||||
@@ -29,6 +29,9 @@ If you can't access {% data variables.product.product_name %}, contact your loca
|
||||
|
||||
{% data reusables.saml.dotcom-saml-explanation %} Organization owners can invite your user account on {% data variables.product.prodname_dotcom %} to join their organization that uses SAML SSO, which allows you to contribute to the organization and retain your existing identity and contributions on {% data variables.product.prodname_dotcom %}.
|
||||
|
||||
If you're a member of an {% data variables.product.prodname_emu_enterprise %}, you will use a new account that is provisioned for you. {% data reusables.enterprise-accounts.emu-more-info-account %}
|
||||
|
||||
|
||||
When you access resources within an organization that uses SAML SSO, {% data variables.product.prodname_dotcom %} will redirect you to the organization's SAML IdP to authenticate. After you successfully authenticate with your account on the IdP, the IdP redirects you back to {% data variables.product.prodname_dotcom %}, where you can access the organization's resources.
|
||||
|
||||
{% data reusables.saml.outside-collaborators-exemption %}
|
||||
|
||||
@@ -27,6 +27,10 @@ You can access your resources in {% data variables.product.product_name %} in a
|
||||
|
||||
You can authenticate to {% data variables.product.product_name %} in your browser {% ifversion ghae %}using your IdP. For more information, see "[About authentication with SAML single sign-on](/github/authenticating-to-github/about-authentication-with-saml-single-sign-on)."{% else %}in different ways.
|
||||
|
||||
- {% ifversion fpt %}
|
||||
If you're a member of an {% data variables.product.prodname_emu_enterprise %}, you will authenticate to {% data variables.product.product_name %} in your browser using your IdP. For more information, see "[Authenticating as a managed user](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/about-enterprise-managed-users#authenticating-as-a-managed-user)". If you're not a member of an {% data variables.product.prodname_emu_enterprise %}, you will authenticate using your browser on {% data variables.product.prodname_dotcom_the_website %}.
|
||||
{% endif %}
|
||||
|
||||
- **Username and password only**
|
||||
- You'll create a password when you create your user account on {% data variables.product.product_name %}. We recommend that you use a password manager to generate a random and unique password. For more information, see "[Creating a strong password](/github/authenticating-to-github/creating-a-strong-password)."
|
||||
- **Two-factor authentication (2FA)** (recommended)
|
||||
|
||||
@@ -38,8 +38,7 @@ A token with no assigned scopes can only access public information. To use your
|
||||
{% data reusables.user_settings.access_settings %}
|
||||
{% data reusables.user_settings.developer_settings %}
|
||||
{% data reusables.user_settings.personal_access_tokens %}
|
||||
4. Click **Generate new token**.
|
||||

|
||||
{% data reusables.user_settings.generate_new_token %}
|
||||
5. Give your token a descriptive name.
|
||||
{% ifversion fpt or ghes > 3.2 or ghae-issue-4374 %}
|
||||
6. To give your token an expiration, select the **Expiration** drop-down menu, then click a default or use the calendar picker.
|
||||
|
||||
@@ -79,34 +79,6 @@ You can use a fallback number regardless of whether you've configured authentica
|
||||
|
||||
After setup, the backup device will receive a confirmation SMS.
|
||||
|
||||
## Adding a fallback authentication method with Recover Accounts Elsewhere
|
||||
|
||||
You can generate an extra authentication credential for your account and store it with a partner recovery provider.
|
||||
|
||||
### About Recover Accounts Elsewhere
|
||||
|
||||
With Recover Accounts Elsewhere, you can add an extra security factor to your {% data variables.product.product_name %} account in case you lose access to your two-factor authentication method or recovery codes.
|
||||
|
||||
Recover Accounts Elsewhere lets you associate your {% data variables.product.product_name %} account with your Facebook account. You can store an authentication credential in the form of an _account recovery token_ for your {% data variables.product.product_name %} account with Facebook.
|
||||
|
||||
If you lose access to your {% data variables.product.product_name %} account because you no longer have access to your two-factor authentication method or recovery codes, you can retrieve your account recovery token from the recovery provider to help prove that you're the owner of your {% data variables.product.product_name %} account.
|
||||
|
||||
After you retrieve your token, {% data variables.contact.contact_support %} may be able to disable two-factor authentication for your account. Then, you can provide or reset your password to regain access to your account.
|
||||
|
||||
When you generate or retrieve an account recovery token, an event is added to your account's audit log. For more information, see "[Reviewing your security log](/articles/reviewing-your-security-log)."
|
||||
|
||||
### Generating and storing an account recovery token
|
||||
|
||||
You can generate an account recovery token and store it with a partner recovery provider.
|
||||
|
||||
1. Sign in to your Facebook account, then return to {% data variables.product.product_name %}.
|
||||
{% data reusables.user_settings.access_settings %}
|
||||
{% data reusables.user_settings.security %}
|
||||
4. To generate a new token, under "Recovery tokens," click **Store new token**. 
|
||||
5. Read the information about account recovery tokens, then click **Connect with https://www.facebook.com**. 
|
||||
6. After you're redirected to Facebook, read the information about turning on account recovery with Facebook before you click **Save as [_YOUR NAME_]**. (If you save multiple tokens within a short period of time, Facebook may skip this confirmation step after you save your first token.)
|
||||

|
||||
|
||||
{% endif %}
|
||||
|
||||
## Further reading
|
||||
|
||||
@@ -27,6 +27,12 @@ We strongly recommend using a time-based one-time password (TOTP) application to
|
||||
|
||||
{% endwarning %}
|
||||
|
||||
{% ifversion fpt %}
|
||||
|
||||
If you're a member of an {% data variables.product.prodname_emu_enterprise %}, you cannot configure 2FA for your {% data variables.product.prodname_managed_user %} account. 2FA should be configured through your identity provider.
|
||||
|
||||
{% endif %}
|
||||
|
||||
## Configuring two-factor authentication using a TOTP mobile app
|
||||
|
||||
A time-based one-time password (TOTP) application automatically generates an authentication code that changes after a certain period of time. We recommend using cloud-based TOTP apps such as:
|
||||
|
||||
@@ -78,6 +78,12 @@ You can use your two-factor authentication credentials or two-factor authenticat
|
||||
|
||||
## Authenticating with an account recovery token
|
||||
|
||||
{% warning %}
|
||||
|
||||
**Warning:** Account recovery tokens are deprecated and will be disabled on **December 1st, 2021**. Please ensure you have configured other two-factor recovery methods. For more information, see "[Configuring two-factor authentication recovery methods](/articles/configuring-two-factor-authentication-recovery-methods)."
|
||||
|
||||
{% endwarning %}
|
||||
|
||||
If you lose access to the two-factor authentication methods for your {% data variables.product.product_name %} account, you can retrieve your account recovery token from a partner recovery provider and ask {% data variables.product.prodname_dotcom %} Support to review it.
|
||||
|
||||
If you don't have access to your two-factor authentication methods or recovery codes and you've stored an account recovery token with Facebook using Recover Accounts Elsewhere, you may be able to use your token to regain access to your account.
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
---
|
||||
title: About dependency review
|
||||
intro: 'Dependency review lets you catch vulnerable dependencies before you introduce them to your environment, and provides information on license, dependents, and age of dependencies.'
|
||||
product: '{% data reusables.gated-features.dependency-review %}'
|
||||
shortTitle: Dependency review
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '>= 3.2'
|
||||
product: '{% data reusables.gated-features.dependency-review %}'
|
||||
type: overview
|
||||
topics:
|
||||
- Advanced Security
|
||||
|
||||
@@ -15,6 +15,5 @@ children:
|
||||
- /forwarding-ports-in-your-codespace
|
||||
- /changing-the-machine-type-for-your-codespace
|
||||
- /using-codespaces-in-visual-studio-code
|
||||
- /web-based-editor
|
||||
---
|
||||
|
||||
|
||||
@@ -30,11 +30,7 @@ A typical workflow for updating a file using {% data variables.product.prodname_
|
||||
|
||||
## Creating or switching branches
|
||||
|
||||
1. If the current branch is not shown in the status bar, at the bottom of your codespace, right-click the status bar and select **Source control**.
|
||||
1. Click the branch name in the status bar.
|
||||

|
||||
1. In the drop-down, either click the branch you want to switch to, or enter the name for a new branch and click **Create new branch**.
|
||||

|
||||
{% data reusables.codespaces.create-or-switch-branch %}
|
||||
|
||||
{% tip %}
|
||||
|
||||
@@ -70,21 +66,11 @@ If the fetch operation detects new changes on the remote repository, you'll see
|
||||
|
||||
## Committing your changes
|
||||
|
||||
{% data reusables.codespaces.source-control-display-dark %}
|
||||
1. To stage your changes, click **+** next to the file you've changed, or next to **Changes** if you've changed multiple files and you want to stage them all.
|
||||

|
||||
1. Type a commit message describing the change you've made.
|
||||

|
||||
1. To commit your staged changes, click the check mark at the top the source control side bar.
|
||||

|
||||
{% data reusables.codespaces.source-control-commit-changes %}
|
||||
|
||||
## Raising a pull request
|
||||
|
||||
1. After you've committed changes to your local copy of the repository, click the **Create Pull Request** icon.
|
||||

|
||||
1. Check that the local branch and repository you're merging from, and the remote branch and repository you're merging into, are correct. Then give the pull request a title and a description.
|
||||

|
||||
1. Click **Create**.
|
||||
{% data reusables.codespaces.source-control-pull-request %}
|
||||
|
||||
## Pushing changes to your remote repository
|
||||
|
||||
|
||||
@@ -24,9 +24,6 @@ featuredLinks:
|
||||
- /codespaces/setting-up-your-codespace/personalizing-codespaces-for-your-account
|
||||
popularHeading: Set up your project
|
||||
product_video: 'https://www.youtube-nocookie.com/embed/_W9B7qc9lVc'
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/codespaces-feedback'
|
||||
redirect_from:
|
||||
- /github/developing-online-with-github-codespaces
|
||||
- /github/developing-online-with-codespaces
|
||||
@@ -44,6 +41,7 @@ children:
|
||||
- /managing-codespaces-for-your-organization
|
||||
- /codespaces-reference
|
||||
- /troubleshooting
|
||||
- /the-githubdev-web-based-editor
|
||||
- /guides
|
||||
---
|
||||
|
||||
|
||||
106
content/codespaces/the-githubdev-web-based-editor.md
Normal file
@@ -0,0 +1,106 @@
|
||||
---
|
||||
title: The github.dev web-based editor
|
||||
intro: Use the github.dev {% data variables.product.prodname_serverless %} from your repository or pull request to create and commit changes.
|
||||
versions:
|
||||
fpt: '*'
|
||||
type: how_to
|
||||
miniTocMaxHeadingLevel: 3
|
||||
topics:
|
||||
- Codespaces
|
||||
- Visual Studio Code
|
||||
- Developer
|
||||
shortTitle: Web-based editor
|
||||
redirect_from:
|
||||
- /codespaces/developing-in-codespaces/web-based-editor
|
||||
---
|
||||
|
||||
{% note %}
|
||||
|
||||
**Note:** The github.dev {% data variables.product.prodname_serverless %} is currently in beta preview. You can provide feedback [in our Discussions](https://github.co/browser-editor-feedback).
|
||||
|
||||
{% endnote %}
|
||||
|
||||
## About the {% data variables.product.prodname_serverless %}
|
||||
|
||||
The {% data variables.product.prodname_serverless %} introduces a lightweight editing experience that runs entirely in your browser. With the {% data variables.product.prodname_serverless %}, you can navigate files and source code repositories from {% data variables.product.prodname_dotcom %}, and make and commit code changes. You can open any repository, fork, or pull request in the editor.
|
||||
|
||||
The {% data variables.product.prodname_serverless %} is available to everyone for free on {% data variables.product.prodname_dotcom_the_website %}.
|
||||
|
||||
The {% data variables.product.prodname_serverless %} provides many of the benefits of {% data variables.product.prodname_vscode %}, such as search, syntax highlighting, and a source control view. You can also use Settings Sync to share your own {% data variables.product.prodname_vscode %} settings with the editor. For more information, see "[Settings Sync](https://code.visualstudio.com/docs/editor/settings-sync)" in the {% data variables.product.prodname_vscode %} documentation.
|
||||
|
||||
The {% data variables.product.prodname_serverless %} runs entirely in your browser’s sandbox. The editor doesn’t clone the repository, but instead uses the [GitHub Repositories extension](https://code.visualstudio.com/docs/editor/github#_github-repositories-extension) to carry out most of the functionality that you will use. Your work is saved in the browser’s local storage until you commit it. You should commit your changes regularly to ensure that they're always accessible.
|
||||
|
||||
## Opening the {% data variables.product.prodname_serverless %}
|
||||
|
||||
You can open any {% data variables.product.prodname_dotcom %} repository in the {% data variables.product.prodname_serverless %} in the following ways:
|
||||
|
||||
- Press `.` while browsing any repository or pull request on {% data variables.product.prodname_dotcom %}.
|
||||
- Change the URL from "github.com" to "github.dev".
|
||||
|
||||
## {% data variables.product.prodname_codespaces %} and the {% data variables.product.prodname_serverless %}
|
||||
|
||||
Both the {% data variables.product.prodname_serverless %} and {% data variables.product.prodname_codespaces %} allow you to edit your code straight from your repository. However, both have slightly different benefits, depending on your use case.
|
||||
|
||||
|| {% data variables.product.prodname_serverless %} | {% data variables.product.prodname_codespaces %}|
|
||||
|-|----------------|---------|
|
||||
| **Cost** | Free. | Costs for compute and storage. For information on pricing, see "[Codespaces pricing](/en/billing/managing-billing-for-github-codespaces/about-billing-for-codespaces#codespaces-pricing)."|
|
||||
| **Availability** | Available to everyone on GitHub.com. | Available for organizations using GitHub Team or GitHub Enterprise Cloud. |
|
||||
| **Start up** | The {% data variables.product.prodname_serverless %} opens instantly with a key-press and you can start using it right away, without having to wait for additional configuration or installation. | When you create or resume a codespace, the codespace is assigned a VM and the container is configured based on the contents of a `devcontainer.json` file. This set up may take a few minutes to create the environment. For more information, see "[Creating a Codespace](/codespaces/developing-in-codespaces/creating-a-codespace)." |
|
||||
| **Compute** | There is no associated compute, so you won’t be able to build and run your code or use the integrated terminal. | With {% data variables.product.prodname_codespaces %}, you get the power of dedicated VM on which you can run and debug your application.|
|
||||
| **Terminal access** | None. | {% data variables.product.prodname_codespaces %} provides a common set of tools by default, meaning that you can use the Terminal exactly as you would in your local environment.|
|
||||
| **Extensions** | Only a subset of extensions that can run in the web will appear in the Extensions View and can be installed. For more information, see "[Using extensions](#using-extensions)."| With Codespaces, you can use most extensions from the Visual Studio Code Marketplace.|
|
||||
|
||||
### Continue working on {% data variables.product.prodname_codespaces %}
|
||||
|
||||
You can start your workflow in the {% data variables.product.prodname_serverless %} and continue working on a codespace, provided you have [access to {% data variables.product.prodname_codespaces %}](/codespaces/developing-in-codespaces/creating-a-codespace#access-to-codespaces). If you try to access the Run and Debug View or the Terminal, you'll be notified that they are not available in the {% data variables.product.prodname_serverless %}.
|
||||
|
||||
To continue your work in a codespace, click **Continue Working on…** and select **Create New Codespace** to create a codespace on your current branch. Before you choose this option, you must commit any changes.
|
||||
|
||||

|
||||
|
||||
## Using source control
|
||||
|
||||
When you use the {% data variables.product.prodname_serverless %}, all actions are managed through the Source Control View, which is located in the Activity Bar on the left hand side. For more information on the Source Control View, see "[Version Control](https://code.visualstudio.com/docs/editor/versioncontrol)" in the {% data variables.product.prodname_vscode %} documentation.
|
||||
|
||||
Because the web-based editor uses the GitHub Repositories extension to power its functionality, you can switch branches without needing to stash changes. For more information, see "[GitHub Repositories](https://code.visualstudio.com/docs/editor/github#_github-repositories-extension)" in the {% data variables.product.prodname_vscode %} documentation.
|
||||
|
||||
### Create a new branch
|
||||
|
||||
{% data reusables.codespaces.create-or-switch-branch %}
|
||||
Any uncommited changes you have made in your old branch will be available on your new branch.
|
||||
|
||||
### Commit your changes
|
||||
|
||||
{% data reusables.codespaces.source-control-commit-changes %}
|
||||
5. Once you have committed your changes, they will automatically be pushed to your branch on {% data variables.product.prodname_dotcom %}.
|
||||
### Create a pull request
|
||||
|
||||
{% data reusables.codespaces.source-control-pull-request %}
|
||||
|
||||
### Working with an existing pull request
|
||||
|
||||
You can use the {% data variables.product.prodname_serverless %} to work with an existing pull request.
|
||||
|
||||
1. Browse to the pull request you'd like to open in the {% data variables.product.prodname_serverless %}.
|
||||
2. Press `.` to open the pull request in the {% data variables.product.prodname_serverless %}.
|
||||
3. Once you have made any changes, commit them using the steps in [Commit your changes](#commit-your-changes). Your changes will be committed directly to the branch, it's not necessary to push the changes.
|
||||
|
||||
## Using extensions
|
||||
|
||||
The {% data variables.product.prodname_serverless %} supports {% data variables.product.prodname_vscode %} extensions that have been specifically created or updated to run in the web. These extensions are known as "web extensions". To learn how you can create a web extension or update your existing extension to work for the web, see "[Web extensions](https://code.visualstudio.com/api/extension-guides/web-extensions)" in the {% data variables.product.prodname_vscode %} documentation.
|
||||
|
||||
Extensions that can run in the {% data variables.product.prodname_serverless %} will appear in the Extensions View and can be installed. If you use Settings Sync, any compatible extensions are also installed automatically. For information, see "[Settings Sync](https://code.visualstudio.com/docs/editor/settings-sync)" in the {% data variables.product.prodname_vscode %} documentation.
|
||||
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If you have issues opening the {% data variables.product.prodname_serverless %}, try the following:
|
||||
|
||||
- Make sure you are signed in to {% data variables.product.prodname_dotcom %}.
|
||||
- Disable any ad blockers.
|
||||
- Use a non-incognito window in your browser to open the {% data variables.product.prodname_serverless %}.
|
||||
|
||||
### Known limitations
|
||||
|
||||
- The {% data variables.product.prodname_serverless %} is currently supported in Chrome (and various other Chromium-based browsers), Edge, Firefox, and Safari. We recommend that you use the latest versions of these browsers.
|
||||
- Some keybindings may not work, depending on the browser you are using. These keybinding limitations are documented in the "[Known limitations and adaptations](https://code.visualstudio.com/docs/remote/codespaces#_known-limitations-and-adaptations)" section of the {% data variables.product.prodname_vscode %} documentation.
|
||||
@@ -31,7 +31,7 @@ Different server-to-server request rate limits apply to {% data variables.produc
|
||||
|
||||
### {% data variables.product.prodname_ghe_cloud %} server-to-server rate limits
|
||||
|
||||
{% data variables.product.prodname_github_apps %} that are installed on an organization or repository owned by a {% data variables.product.prodname_ghe_cloud %} account and make server-to-server requests have a rate limit of 15,000 requests per hour.
|
||||
{% data variables.product.prodname_github_apps %} that are installed on an organization or repository owned by a {% data variables.product.prodname_ghe_cloud %} account and make server-to-server requests have a rate limit of 15,000 requests per hour per organization for organization installations or per repository for repository installations.
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Collaborating with maintainers using discussions
|
||||
shortTitle: Collaborating with maintainers
|
||||
intro: 'You can contribute to the goals, plans, health, and community for a project on {% data variables.product.product_name %} by communicating with the maintainers of the project in a discussion.'
|
||||
permissions: People with read permissions to a repository can start and participate in discussions in the repository.
|
||||
permissions: 'People with read access to a repository can start and participate in discussions in the repository. {% data reusables.enterprise-accounts.emu-permission-interact %}'
|
||||
versions:
|
||||
fpt: '*'
|
||||
---
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Participating in a discussion
|
||||
intro: 'You can converse with the community and maintainers in a forum within the repository for a project on {% data variables.product.product_name %}.'
|
||||
permissions: People with read permissions to a repository can participate in discussions in the repository.
|
||||
permissions: 'People with read access to a repository can participate in discussions in the repository. {% data reusables.enterprise-accounts.emu-permission-interact %}'
|
||||
versions:
|
||||
fpt: '*'
|
||||
shortTitle: Participate in discussion
|
||||
|
||||
@@ -26,9 +26,6 @@ changelog:
|
||||
examples_source: data/product-examples/discussions/community-examples.yml
|
||||
product_video: 'https://www.youtube-nocookie.com/embed/IpBw2SJkFyk'
|
||||
layout: product-landing
|
||||
community_redirect:
|
||||
name: Provide GitHub Feedback
|
||||
href: 'https://github.com/github/feedback/discussions/categories/discussions-feedback'
|
||||
versions:
|
||||
fpt: '*'
|
||||
children:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Finding ways to contribute to open source on GitHub
|
||||
intro: 'You can find ways to contribute to open source projects on {% data variables.product.product_name %} that are relevant to you.'
|
||||
permissions: '{% data reusables.enterprise-accounts.emu-permission-interact %}'
|
||||
redirect_from:
|
||||
- /articles/where-can-i-find-open-source-projects-to-work-on/
|
||||
- /articles/finding-interesting-projects-on-github/
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Following people
|
||||
intro: 'You can follow people on {% data variables.product.product_name %} to receive notifications about their activity{% ifversion fpt %} and discover projects in their communities{% endif %}.'
|
||||
permissions: '{% data reusables.enterprise-accounts.emu-permission-follow %}'
|
||||
redirect_from:
|
||||
- /articles/following-people
|
||||
- /github/getting-started-with-github/following-people
|
||||
|
||||
@@ -35,6 +35,8 @@ Organization members can have *owner*{% ifversion fpt %}, *billing manager*,{% e
|
||||
|
||||
*Enterprise owners* have ultimate power over the enterprise account and can take every action in the enterprise account. *Billing managers* can manage your enterprise account's billing settings. Members and outside collaborators of organizations owned by your enterprise account are automatically members of the enterprise account, although they have no access to the enterprise account itself or its settings. For more information, see "[Roles in an enterprise](/github/setting-up-and-managing-your-enterprise/roles-in-an-enterprise)."
|
||||
|
||||
If an enterprise uses {% data variables.product.prodname_emus %}, members are provisioned as new user accounts on {% data variables.product.prodname_dotcom %} and are fully managed by the identity provider. The {% data variables.product.prodname_managed_users %} have read-only access to repositories that are not a part of their enterprise and cannot interact with users that are not also members of the enterprise. Within the organizations owned by the enterprise, the {% data variables.product.prodname_managed_users %} can be granted the same granular access levels available for regular organizations. For more information, see "[About {% data variables.product.prodname_emus %}](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/about-enterprise-managed-users)."
|
||||
|
||||
{% data reusables.gated-features.enterprise-accounts %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
@@ -101,6 +101,7 @@ In addition to the features available with {% data variables.product.prodname_te
|
||||
- 50GB {% data variables.product.prodname_registry %} storage
|
||||
- Access control for {% data variables.product.prodname_pages %} sites. For more information, see <a href="/pages/getting-started-with-github-pages/changing-the-visibility-of-your-github-pages-site" class="dotcom-only">Changing the visibility of your {% data variables.product.prodname_pages %} site</a>"
|
||||
- A service level agreement for 99.9% monthly uptime
|
||||
- The option to configure your enterprise for {% data variables.product.prodname_emus %}, so you can provision and manage members with your identity provider and restrict your member's contributions to just your enterprise. For more information, see "<a href="/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/about-enterprise-managed-users" class="dotcom-only">About {% data variables.product.prodname_emus %}</a>."
|
||||
- The option to centrally manage policy and billing for multiple {% data variables.product.prodname_dotcom_the_website %} organizations with an enterprise account. For more information, see "<a href="/articles/about-enterprise-accounts" class="dotcom-only">About enterprise accounts</a>."
|
||||
|
||||
You can set up a trial to evaluate {% data variables.product.prodname_ghe_cloud %}. For more information, see "<a href="/articles/setting-up-a-trial-of-github-enterprise-cloud" class="dotcom-only">Setting up a trial of {% data variables.product.prodname_ghe_cloud %}</a>."
|
||||
|
||||
@@ -63,6 +63,14 @@ Every person who uses {% data variables.product.product_location %} has their ow
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% ifversion fpt %}
|
||||
### {% data variables.product.prodname_emus %}
|
||||
|
||||
With {% data variables.product.prodname_emus %}, instead of using your personal account, members of an {% data variables.product.prodname_emu_enterprise %} are provisioned accounts using the enterprise's identity provider (IdP). {% data variables.product.prodname_managed_users_caps %} authenticate using their IdP instead of a {% data variables.product.prodname_dotcom_the_website %} username and password.
|
||||
|
||||
{% data variables.product.prodname_managed_users_caps %} can only interact with users, repositories, and organizations that are part of their enterprise. {% data variables.product.prodname_managed_users_caps %} have read-only access to the rest of {% data variables.product.prodname_dotcom_the_website %}. For more information, see "[About {% data variables.product.prodname_emus %}](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/about-enterprise-managed-users)."
|
||||
{% endif %}
|
||||
|
||||
## Organization accounts
|
||||
|
||||
Organizations are shared accounts where groups of people can collaborate across many projects at once. Owners and administrators can manage member access to the organization's data and projects with sophisticated security and administrative features.
|
||||
|
||||
@@ -18,16 +18,19 @@ This guide will walk you through setting up, configuring and managing your {% da
|
||||
|
||||
The main difference between the products is that {% data variables.product.prodname_ghe_cloud %} is hosted by {% data variables.product.prodname_dotcom %}, while {% data variables.product.prodname_ghe_server %} is self-hosted.
|
||||
|
||||
Within the {% data variables.product.prodname_ghe_cloud %} product, there are two different types of account that you can use:
|
||||
With {% data variables.product.prodname_ghe_cloud %}, you have the option of using {% data variables.product.prodname_emus %}. {% data reusables.enterprise-accounts.emu-short-summary %}
|
||||
|
||||
If you choose to let your members create and manage their own user accounts instead, there are two types of accounts you can use with {% data variables.product.prodname_ghe_cloud %}:
|
||||
|
||||
- A single organization account
|
||||
- An enterprise account that contains multiple organizations
|
||||
|
||||
In either scenario, your users will use their own self-created user account and you'll invite them to join.
|
||||
### 1. Understanding the differences between an organization account and enterprise account
|
||||
|
||||
Both organization and enterprise accounts are available with {% data variables.product.prodname_ghe_cloud %}. An organization is a shared account where groups of people can collaborate across many projects at once, and owners and administrators can manage access to data and projects. An enterprise account enables collaboration between multiple organizations, and allows owners to centrally manage policy, billing and security for these organizations. For more information on the differences, see "[Organizations and enterprise accounts](/organizations/collaborating-with-groups-in-organizations/about-organizations#organizations-and-enterprise-accounts)."
|
||||
|
||||
|
||||
|
||||
If you choose an enterprise account, keep in mind that some policies can be set only at an organization level, while others can be enforced for all organizations in an enterprise.
|
||||
|
||||
Once you choose the account type you would like, you can proceed to setting up your account. In each of the sections in this guide, proceed to either the single organization or enterprise account section based on your account type.
|
||||
@@ -86,6 +89,11 @@ You can set permissions and member roles, create and manage teams, and give peop
|
||||
|
||||
### Managing members of an enterprise account
|
||||
Managing members of an enterprise is separate from managing members or teams in an organization. It is important to note that enterprise owners or administrators cannot access organization-level settings or manage members for organizations in their enterprise unless they are made an organization owner. For more information, see the above section, "[Managing members and teams in your organization](#managing-members-and-teams-in-your-organization)."
|
||||
|
||||
If your enterprise uses {% data variables.product.prodname_emus %}, your members are fully managed through your identity provider. Adding members, making changes to their membership, and assigning roles is all managed using your IdP. For more information, see "[About {% data variables.product.prodname_emus %}](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/about-enterprise-managed-users)."
|
||||
|
||||
If your enterprise does not use {% data variables.product.prodname_emus %}, follow the steps below.
|
||||
|
||||
#### 1. Assigning roles in an enterprise
|
||||
By default, everyone in an enterprise is a member of the enterprise. There are also administrative roles, including enterprise owner and billing manager, that have different levels of access to enterprise settings and data. For more information, see "[Roles in an enterprise](/github/setting-up-and-managing-your-enterprise/managing-users-in-your-enterprise/roles-in-an-enterprise)."
|
||||
#### 2. Inviting people to manage your enterprise
|
||||
@@ -97,6 +105,10 @@ To audit access to enterprise-owned resources or user license usage, you can vie
|
||||
|
||||
## Part 4: Managing security with {% data variables.product.prodname_ghe_cloud %}
|
||||
|
||||
* [Managing security for a single organization](#managing-security-for-a-single-organization)
|
||||
* [Managing security for an {% data variables.product.prodname_emu_enterprise %}](#managing-security-for-an-enterprise-with-managed-users)
|
||||
* [Managing security for an enterprise account without {% data variables.product.prodname_managed_users %}](#managing-security-for-an-enterprise-account-without-managed-users)
|
||||
|
||||
### Managing security for a single organization
|
||||
You can help keep your organization secure by requiring two-factor authentication, configuring security features, reviewing your organization's audit log and integrations, and enabling SAML single sign-on and team synchronization.
|
||||
#### 1. Requiring two-factor authentication
|
||||
@@ -113,8 +125,28 @@ Organization owners can choose to disable, enable but not enforce, or enable and
|
||||
#### 5. Managing team synchronization for your organization
|
||||
Organization owners can enable team synchronization between your identity provider (IdP) and {% data variables.product.prodname_dotcom %} to allow organization owners and team maintainers to connect teams in your organization with IdP groups. For more information, see "[Managing team synchronization for your organization](/organizations/managing-saml-single-sign-on-for-your-organization/managing-team-synchronization-for-your-organization)."
|
||||
|
||||
### Managing security for an enterprise account with multiple organizations
|
||||
### Managing security for an {% data variables.product.prodname_emu_enterprise %}
|
||||
|
||||
With {% data variables.product.prodname_emus %}, access and identity is managed centrally through your identity provider. Two-factor authentication and other login requirements should be enabled and enforced on your IdP.
|
||||
|
||||
#### 1. Enabling and SAML single sign-on and provisioning in your {% data variables.product.prodname_emu_enterprise %}
|
||||
|
||||
In an {% data variables.product.prodname_emu_enterprise %}, all members are provisioned and managed by your identity provider. You must enable SAML SSO and SCIM provisioning before you can start using your enterprise. For more information on configuring SAML SSO and provisioning for an {% data variables.product.prodname_emu_enterprise %}, see "[Configuring SAML single sign-on for Enterprise Managed Users](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/configuring-saml-single-sign-on-for-enterprise-managed-users)."
|
||||
|
||||
#### 2. Managing teams in your {% data variables.product.prodname_emu_enterprise %} with your identity provider
|
||||
|
||||
You can connect teams in your organizations to security groups in your identity provider, managing membership of your teams and access to repositories through your IdP. For more information, see "[Managing team memberships with identity provider groups](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/managing-team-memberships-with-identity-provider-groups)."
|
||||
|
||||
#### 3. Managing allowed IP addresses for organizations in your {% data variables.product.prodname_emu_enterprise %}
|
||||
|
||||
You can configure an allow list for specific IP addresses to restrict access to assets owned by organizations in your {% data variables.product.prodname_emu_enterprise %}. For more information, see "[Enforcing security settings in your enterprise account](/github/setting-up-and-managing-your-enterprise/setting-policies-for-organizations-in-your-enterprise-account/enforcing-security-settings-in-your-enterprise-account#managing-allowed-ip-addresses-for-organizations-in-your-enterprise-account)."
|
||||
|
||||
#### 4. Enforcing policies for Advanced Security features in your {% data variables.product.prodname_emu_enterprise %}
|
||||
{% data reusables.getting-started.enterprise-advanced-security %}
|
||||
|
||||
### Managing security for an enterprise account without {% data variables.product.prodname_managed_users %}
|
||||
To manage security for your enterprise, you can require two-factor authentication, manage allowed IP addresses, enable SAML single sign-on and team synchronization at an enterprise level, and sign up for and enforce GitHub Advanced Security features.
|
||||
|
||||
#### 1. Requiring two-factor authentication and managing allowed IP addresses for organizations in your enterprise account
|
||||
Enterprise owners can require that organization members, billing managers, and outside collaborators in all organizations owned by an enterprise account use two-factor authentication to secure their personal accounts. Before doing so, we recommend notifying all who have access to organizations in your enterprise. You can also configure an allow list for specific IP addresses to restrict access to assets owned by organizations in your enterprise account.
|
||||
|
||||
@@ -126,7 +158,7 @@ You can centrally manage access to your enterprise's resources, organization mem
|
||||
You can enable and manage team sychronization between an identity provider (IdP) and {% data variables.product.prodname_dotcom %} to allow organizations owned by your enterprise account to manage team membership with IdP groups. For more information, see "[Managing team synchronization for organizations in your enterprise account](/github/setting-up-and-managing-your-enterprise/configuring-identity-and-access-management-for-your-enterprise-account/managing-team-synchronization-for-organizations-in-your-enterprise-account)."
|
||||
|
||||
#### 4. Enforcing policies for Advanced Security features in your enterprise account
|
||||
If you have a GitHub Advanced Security license for your enterprise account, you can enforce policies to manage {% data variables.product.prodname_dotcom %} Advanced Security features for organizations owned by an enterprise account. For more information, see "[Enforcing policies for Advanced Security in your enterprise account](/github/setting-up-and-managing-your-enterprise/setting-policies-for-organizations-in-your-enterprise-account/enforcing-policies-for-advanced-security-in-your-enterprise-account)."
|
||||
{% data reusables.getting-started.enterprise-advanced-security %}
|
||||
|
||||
## Part 5: Managing organization and enterprise level policies and settings
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ redirect_from:
|
||||
- /github/getting-started-with-github/be-social
|
||||
- /github/getting-started-with-github/quickstart/be-social
|
||||
intro: 'You can interact with people, repositories, and organizations on {% data variables.product.prodname_dotcom %}. See what others are working on and who they''re connecting with from your personal dashboard.'
|
||||
permissions: '{% data reusables.enterprise-accounts.emu-permission-interact %}'
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
|
||||
@@ -7,6 +7,7 @@ redirect_from:
|
||||
- /github/getting-started-with-github/fork-a-repo
|
||||
- /github/getting-started-with-github/quickstart/fork-a-repo
|
||||
intro: A fork is a copy of a repository. Forking a repository allows you to freely experiment with changes without affecting the original project.
|
||||
permissions: '{% data reusables.enterprise-accounts.emu-permission-fork %}'
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
|
||||
@@ -5,7 +5,7 @@ redirect_from:
|
||||
- /github/collaborating-with-issues-and-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork
|
||||
- /articles/creating-a-pull-request-from-a-fork
|
||||
- /github/collaborating-with-issues-and-pull-requests/creating-a-pull-request-from-a-fork
|
||||
permissions: Anyone with write access to a repository can create a pull request from a user-owned fork.
|
||||
permissions: 'Anyone with write access to a repository can create a pull request from a user-owned fork. {% data reusables.enterprise-accounts.emu-permission-propose %}'
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Creating a pull request
|
||||
intro: 'Create a pull request to propose and collaborate on changes to a repository. These changes are proposed in a *branch*, which ensures that the default branch only contains finished and approved work.'
|
||||
permissions: 'Anyone with read access to a repository can create a pull request. {% data reusables.enterprise-accounts.emu-permission-propose %}'
|
||||
redirect_from:
|
||||
- /github/collaborating-with-issues-and-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request
|
||||
- /articles/creating-a-pull-request
|
||||
@@ -12,7 +13,7 @@ versions:
|
||||
topics:
|
||||
- Pull requests
|
||||
---
|
||||
Anyone with read permissions to a repository can create a pull request, but you must have write permissions to create a branch. If you want to create a new branch for your pull request and don't have write permissions to the repository, you can fork the repository first. For more information, see "[Creating a pull request from a fork](/articles/creating-a-pull-request-from-a-fork)" and "[About forks](/articles/about-forks)."
|
||||
If you want to create a new branch for your pull request and do not have write permissions to the repository, you can fork the repository first. For more information, see "[Creating a pull request from a fork](/articles/creating-a-pull-request-from-a-fork)" and "[About forks](/articles/about-forks)."
|
||||
|
||||
You can specify which branch you'd like to merge your changes into when you create your pull request. Pull requests can only be opened between two branches that are different.
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
title: Reviewing dependency changes in a pull request
|
||||
intro: 'If a pull request contains changes to dependencies, you can view a summary of what has changed and whether there are known vulnerabilities in any of the dependencies.'
|
||||
product: '{% data reusables.gated-features.dependency-review %}'
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '>= 3.2'
|
||||
product: '{% data reusables.gated-features.dependency-review %}'
|
||||
type: how_to
|
||||
topics:
|
||||
- Pull requests
|
||||
@@ -38,18 +38,19 @@ Dependency review allows you to "shift left". You can use the provided predictiv
|
||||
1. If the pull request contains many files, use the **File filter** drop-down menu to collapse all files that don't record dependencies. This will make it easier to focus your review on the dependency changes.
|
||||
|
||||

|
||||
The dependency review provides a clearer view of what has changed in large lock files, where the source diff is not rendered by default.
|
||||
|
||||
{% note %}
|
||||
|
||||
**Note:** Dependency review rich diffs are not available for committed static JavaScript files like `jquery.js`.
|
||||
|
||||
{% endnote %}
|
||||
|
||||
1. On the right of the header for a manifest or lock file, display the dependency review by clicking the **{% octicon "file" aria-label="The rich diff icon" %}** rich diff button.
|
||||
|
||||

|
||||
|
||||
{% note %}
|
||||
|
||||
**Note:** The dependency review provides a clearer view of what has changed in large lock files, where the source diff is not rendered by default.
|
||||
|
||||
{% endnote %}
|
||||
|
||||
1. Check the dependencies listed in the dependency review.
|
||||
2. Check the dependencies listed in the dependency review.
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -19,6 +19,12 @@ Forking a repository is similar to copying a repository, with two major differen
|
||||
|
||||
{% data reusables.repositories.you-can-fork %}
|
||||
|
||||
{% ifversion fpt %}
|
||||
|
||||
If you're a member of a {% data variables.product.prodname_emu_enterprise %}, there are further restrictions on the repositories you can fork. {% data reusables.enterprise-accounts.emu-forks %} For more information, see "[About {% data variables.product.prodname_emus %}](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/about-enterprise-managed-users)."
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% data reusables.repositories.desktop-fork %}
|
||||
|
||||
Deleting a fork will not delete the original upstream repository. You can make any changes you want to your fork—add collaborators, rename files, generate {% data variables.product.prodname_pages %}—with no effect on the original.{% ifversion fpt %} You cannot restore a deleted forked repository. For more information, see "[Restoring a deleted repository](/articles/restoring-a-deleted-repository)."{% endif %}
|
||||
|
||||
@@ -20,6 +20,12 @@ If you use Azure AD as your IDP, you can use team synchronization to manage team
|
||||
|
||||
{% data reusables.saml.switching-from-org-to-enterprise %} For more information, see "[Switching your SAML configuration from an organization to an enterprise account](/github/setting-up-and-managing-your-enterprise/configuring-identity-and-access-management-for-your-enterprise-account/switching-your-saml-configuration-from-an-organization-to-an-enterprise-account)."
|
||||
|
||||
## About {% data variables.product.prodname_emus %}
|
||||
|
||||
{% data reusables.enterprise-accounts.emu-short-summary %}
|
||||
|
||||
Configuring {% data variables.product.prodname_emus %} for SAML single-sign on and user provisioning involves following a different process than you would for an enterprise that isn't using {% data variables.product.prodname_managed_users %}. If your enterprise uses {% data variables.product.prodname_emus %}, see "[Configuring SAML single sign-on for Enterprise Managed Users](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/configuring-saml-single-sign-on-for-enterprise-managed-users)."
|
||||
|
||||
## Supported IdPs
|
||||
|
||||
We test and officially support the following IdPs. For SAML SSO, we offer limited support for all identity providers that implement the SAML 2.0 standard. For more information, see the [SAML Wiki](https://wiki.oasis-open.org/security) on the OASIS website.
|
||||
@@ -31,4 +37,3 @@ Azure Active Directory (Azure AD) | {% octicon "check-circle-fill" aria-label="T
|
||||
OneLogin | {% octicon "check-circle-fill" aria-label="The check icon" %} | |
|
||||
PingOne | {% octicon "check-circle-fill" aria-label="The check icon" %} | |
|
||||
Shibboleth | {% octicon "check-circle-fill" aria-label="The check icon" %} | |
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ shortTitle: Configure SAML with Okta
|
||||
---
|
||||
{% data reusables.enterprise-accounts.user-provisioning-release-stage %}
|
||||
|
||||
{% data reusables.enterprise-accounts.emu-saml-note %}
|
||||
|
||||
## About SAML with Okta
|
||||
|
||||
You can control access to your enterprise account in {% data variables.product.product_name %} and other web applications from one central interface by configuring the enterprise account to use SAML SSO with Okta, an Identity Provider (IdP).
|
||||
|
||||
@@ -12,6 +12,9 @@ redirect_from:
|
||||
- /github/setting-up-and-managing-your-enterprise/enabling-saml-single-sign-on-for-organizations-in-your-enterprise-account
|
||||
shortTitle: Enforce SAML
|
||||
---
|
||||
|
||||
{% data reusables.enterprise-accounts.emu-saml-note %}
|
||||
|
||||
## About SAML single sign-on for enterprise accounts
|
||||
|
||||
{% data reusables.saml.dotcom-saml-explanation %} For more information, see "[About identity and access management with SAML single sign-on](/organizations/managing-saml-single-sign-on-for-your-organization/about-identity-and-access-management-with-saml-single-sign-on)."
|
||||
|
||||
@@ -11,6 +11,9 @@ redirect_from:
|
||||
- /github/setting-up-and-managing-your-enterprise/managing-team-synchronization-for-organizations-in-your-enterprise-account
|
||||
shortTitle: Manage team synchronization
|
||||
---
|
||||
|
||||
{% data reusables.enterprise-accounts.emu-scim-note %}
|
||||
|
||||
## About team synchronization for enterprise accounts
|
||||
|
||||
If you use Azure AD as your IdP, you can enable team synchronization for your enterprise account to allow organization owners and team maintainers to synchronize teams in the organizations owned by your enterprise accounts with IdP groups.
|
||||
|
||||
@@ -10,6 +10,8 @@ topics:
|
||||
shortTitle: Switching from organization
|
||||
---
|
||||
|
||||
{% data reusables.enterprise-accounts.emu-saml-note %}
|
||||
|
||||
## About SAML single sign-on for enterprise accounts
|
||||
|
||||
{% data reusables.saml.dotcom-saml-explanation %} {% data reusables.saml.about-saml-enterprise-accounts %}
|
||||
|
||||
@@ -14,6 +14,7 @@ topics:
|
||||
children:
|
||||
- /managing-your-enterprise-account
|
||||
- /managing-users-in-your-enterprise
|
||||
- /managing-your-enterprise-users-with-your-identity-provider
|
||||
- /managing-organizations-in-your-enterprise-account
|
||||
- /configuring-identity-and-access-management-for-your-enterprise-account
|
||||
- /setting-policies-for-organizations-in-your-enterprise-account
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Adding organizations to your enterprise account
|
||||
intro: You can create new organizations to manage within your enterprise account.
|
||||
intro: You can create new organizations or invite existing organizations to manage within your enterprise account.
|
||||
product: '{% data reusables.gated-features.enterprise-accounts %}'
|
||||
redirect_from:
|
||||
- /articles/adding-organizations-to-your-enterprise-account
|
||||
@@ -12,9 +12,9 @@ topics:
|
||||
- Enterprise
|
||||
shortTitle: Add organizations
|
||||
---
|
||||
Enterprise owners can create new organizations within an enterprise account's settings.
|
||||
Enterprise owners can create new organizations within an enterprise account's settings or invite existing organizations to join an enterprise account.
|
||||
|
||||
To add an organization to your enterprise account, you must create the organization from within the enterprise account settings. If you want to transfer an existing organization to your enterprise account, contact your {% data variables.product.prodname_dotcom %} sales account representative.
|
||||
To add an organization to your enterprise account, you must create the organization from within the enterprise account settings.
|
||||
|
||||
## Creating an organization in your enterprise account
|
||||
|
||||
@@ -31,3 +31,20 @@ Enterprise owners who create an organization owned by the enterprise account aut
|
||||
5. Under "Invite owners", type the username of a person you'd like to invite to become an organization owner, then click **Invite**.
|
||||

|
||||
6. Click **Finish**.
|
||||
|
||||
## Inviting an organization to join your enterprise account
|
||||
|
||||
Enterprise owners can invite existing organizations to join their enterprise account. If the organization you want to invite is already owned by another enterprise, you will not be able to issue an invitation until the previous enterprise gives up ownership of the organization.
|
||||
|
||||
{% data reusables.enterprise-accounts.access-enterprise %}
|
||||
2. On the **Organizations** tab, above the list of organizations, click **Invite organization**.
|
||||

|
||||
3. Under "Organization name", start typing the name of the organization you want to invite and select it when it appears in the drop-down list.
|
||||

|
||||
4. Click **Invite organization**.
|
||||
5. The organization owners will receive an email inviting them to join the organization. At least one owner needs to accept the invitation before the process can continue. You can cancel or resend the invitation at any time before an owner approves it.
|
||||

|
||||
6. Once an organization owner has approved the invitation, you can view its status in the list of pending invitations.
|
||||

|
||||
7. Click **Approve** to complete the transfer, or **Cancel** to cancel it.
|
||||

|
||||
|
||||
@@ -28,6 +28,12 @@ If you want to manage owners and billing managers for an enterprise account on {
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% ifversion fpt %}
|
||||
|
||||
If your enterprise uses {% data variables.product.prodname_emus %}, enterprise owners can only be added or removed through your identity provider. For more information, see "[About {% data variables.product.prodname_emus %}](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/about-enterprise-managed-users)."
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% tip %}
|
||||
|
||||
**Tip:** For more information on managing users within an organization owned by your enterprise account, see "[Managing membership in your organization](/articles/managing-membership-in-your-organization)" and "[Managing people's access to your organization with roles](/articles/managing-peoples-access-to-your-organization-with-roles)."
|
||||
|
||||
@@ -20,7 +20,14 @@ Everyone in an enterprise is a member of the enterprise. You can also assign adm
|
||||
|
||||
{% data reusables.enterprise-accounts.enterprise-administrators %}
|
||||
|
||||
For more information about adding people to your enterprise, see "{% ifversion fpt %}[Inviting people to manage your enterprise](/github/setting-up-and-managing-your-enterprise/inviting-people-to-manage-your-enterprise){% else %}[Authentication](/admin/authentication){% endif %}".
|
||||
{% ifversion fpt %}
|
||||
If your enterprise does not use {% data variables.product.prodname_emus %}, you can invite someone to an administrative role using a user account on {% data variables.product.product_name %} that they control. For more information, see "[Inviting people to manage your enterprise](/github/setting-up-and-managing-your-enterprise/inviting-people-to-manage-your-enterprise)".
|
||||
|
||||
In an enterprise using {% data variables.product.prodname_emus %}, new owners and members must be provisioned through your identity provider. Enterprise owners and organization owners cannot add new members or owners to the enterprise using {% data variables.product.prodname_dotcom %}. You can select a member's enterprise role using your IdP and it cannot be changed on {% data variables.product.prodname_dotcom %}. You can select a member's role in an organization on {% data variables.product.prodname_dotcom %}. For more information, see "[About {% data variables.product.prodname_emus %}](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/about-enterprise-managed-users)."
|
||||
{% else %}
|
||||
For more information about adding people to your enterprise, see "[Authentication](/admin/authentication)".
|
||||
|
||||
{% endif %}
|
||||
|
||||
## Enterprise owner
|
||||
|
||||
|
||||
@@ -17,10 +17,14 @@ shortTitle: View & manage SAML access
|
||||
|
||||
When you enable SAML single sign-on for your enterprise account, each enterprise member can link their external identity on your identity provider (IdP) to their existing {% data variables.product.product_name %} account. {% data reusables.saml.about-saml-access-enterprise-account %}
|
||||
|
||||
If your enterprise is uses {% data variables.product.prodname_emus %}, your members will use accounts provisioned through your IdP. {% data variables.product.prodname_managed_users_caps %} will not use their existing user account on {% data variables.product.product_name %}. For more information, see "[About {% data variables.product.prodname_emus %}](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/about-enterprise-managed-users)."
|
||||
|
||||
## Viewing and revoking a linked identity
|
||||
|
||||
{% data reusables.saml.about-linked-identities %}
|
||||
|
||||
If your enterprise uses {% data variables.product.prodname_emus %}, you will not be able to deprovision or remove user accounts from the enterprise on {% data variables.product.product_name %}. Any changes you need to make to your enterprise's {% data variables.product.prodname_managed_users %} should be made through your IdP.
|
||||
|
||||
{% data reusables.identity-and-permissions.revoking-identity-team-sync %}
|
||||
|
||||
{% data reusables.enterprise-accounts.access-enterprise %}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
---
|
||||
title: About Enterprise Managed Users
|
||||
shortTitle: About managed users
|
||||
intro: You can centrally manage identity and access for your enterprise members on {% data variables.product.prodname_dotcom %} from your identity provider.
|
||||
product: '{% data reusables.gated-features.emus %}'
|
||||
redirect_from:
|
||||
- /early-access/github/articles/get-started-with-managed-users-for-your-enterprise
|
||||
versions:
|
||||
fpt: '*'
|
||||
topics:
|
||||
- Accounts
|
||||
- Enterprise
|
||||
---
|
||||
|
||||
## About {% data variables.product.prodname_emus %}
|
||||
|
||||
With {% data variables.product.prodname_emus %}, you can control the user accounts of your enterprise members through your identity provider (IdP). You can simplify authentication with SAML single sign-on (SSO) and provision, update, and deprovision user accounts for your enterprise members. Users assigned to the {% data variables.product.prodname_emu_idp_application %} application in your IdP are provisioned as new user accounts on {% data variables.product.prodname_dotcom %} and added to your enterprise. You control usernames, profile data, team membership, and repository access from your IdP.
|
||||
|
||||
In your IdP, you can give each {% data variables.product.prodname_managed_user %} the role of user, enterprise owner, or billing manager. {% data variables.product.prodname_managed_users_caps %} can own organizations within your enterprise and can add other {% data variables.product.prodname_managed_users %} to the organizations and teams within. For more information, see "[Roles in an enterprise](/github/setting-up-and-managing-your-enterprise/managing-users-in-your-enterprise/roles-in-an-enterprise)" and "[About organizations](/organizations/collaborating-with-groups-in-organizations/about-organizations)."
|
||||
|
||||
You can also manage team membership within an organization in your enterprise directly through your IdP, allowing you to manage repository access using groups in your IdP. Organization membership can be managed manually or updated automatically as {% data variables.product.prodname_managed_users %} are added to teams within the organization. For more information, see "[Managing team memberships with identity provider groups](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/managing-team-memberships-with-identity-provider-groups)."
|
||||
|
||||
You can grant {% data variables.product.prodname_managed_users %} access and the ability to contribute to repositories within your enterprise, but {% data variables.product.prodname_managed_users %} cannot create public content or collaborate with other users, organizations, and enterprises on the rest of {% data variables.product.prodname_dotcom %}. The {% data variables.product.prodname_managed_users %} provisioned for your enterprise cannot be invited to organizations or repositories outside of the enterprise, nor can the {% data variables.product.prodname_managed_users %} be invited to other enterprises. Outside collaborators are not supported by {% data variables.product.prodname_emus %}.
|
||||
|
||||
The usernames of your enterprise's {% data variables.product.prodname_managed_users %} and their profile information, such as display names and email addresses, are set by through your IdP and cannot be changed by the users themselves. For more information, see "[Usernames and profile information](#usernames-and-profile-information)."
|
||||
|
||||
{% data reusables.enterprise-accounts.emu-forks %}
|
||||
|
||||
Enterprise owners can audit all of the {% data variables.product.prodname_managed_users %}' actions on {% data variables.product.prodname_dotcom %}.
|
||||
|
||||
To use {% data variables.product.prodname_emus %}, you need a separate type of enterprise account with {% data variables.product.prodname_emus %} enabled. For more information about creating this account, see "[About enterprises with managed users](#about-enterprises-with-managed-users)."
|
||||
|
||||
|
||||
## Identity provider support
|
||||
|
||||
{% data variables.product.prodname_emus %} supports the following IdPs:
|
||||
|
||||
{% data reusables.enterprise-accounts.emu-supported-idps %}
|
||||
|
||||
## Abilities and restrictions of {% data variables.product.prodname_managed_users %}
|
||||
|
||||
{% data variables.product.prodname_managed_users_caps %} can only contribute to private and internal repositories within their enterprise and private repositories owned by their user account. {% data variables.product.prodname_managed_users_caps %} have read-only access to the wider {% data variables.product.prodname_dotcom %} community.
|
||||
|
||||
* {% data variables.product.prodname_managed_users_caps %} cannot create issues or pull requests in, comment or add reactions to, nor star, watch, or fork repositories outside of the enterprise.
|
||||
* {% data variables.product.prodname_managed_users_caps %} cannot push code to repositories outside of the enterprise.
|
||||
* {% data variables.product.prodname_managed_users_caps %} and the content they create is only visible to other members of the enterprise.
|
||||
* {% data variables.product.prodname_managed_users_caps %} cannot follow users outside of the enterprise.
|
||||
* {% data variables.product.prodname_managed_users_caps %} cannot create gists or comment on gists.
|
||||
* {% data variables.product.prodname_managed_users_caps %} cannot install {% data variables.product.prodname_github_apps %} on their user accounts.
|
||||
* Other {% data variables.product.prodname_dotcom %} users cannot see, mention, or invite a {% data variables.product.prodname_managed_user %} to collaborate.
|
||||
* {% data variables.product.prodname_managed_users_caps %} can only own private repositories and {% data variables.product.prodname_managed_users %} can only invite other enterprise members to collaborate on their owned repositories.
|
||||
* Only private and internal repositories can be created in organizations owned by an {% data variables.product.prodname_emu_enterprise %}, depending on organization and enterprise repository visibility settings.
|
||||
|
||||
## About enterprises with managed users
|
||||
|
||||
To use {% data variables.product.prodname_emus %}, you need a separate type of enterprise account with {% data variables.product.prodname_emus %} enabled. To try out {% data variables.product.prodname_emus %} or to discuss options for migrating from your existing enterprise, please contact [{% data variables.product.prodname_dotcom %}'s Sales team](https://enterprise.github.com/contact).
|
||||
|
||||
Your contact on the GitHub Sales team will work with you to create your new {% data variables.product.prodname_emu_enterprise %}. You'll need to provide the email address for the user who will set up your enterprise and a short code that will be used as the suffix for your enterprise members' usernames. {% data reusables.enterprise-accounts.emu-shortcode %} For more information, see "[Usernames and profile information](#usernames-and-profile-information)."
|
||||
|
||||
After we create your enterprise, you will receive an email from {% data variables.product.prodname_dotcom %} inviting you to choose a password for your enterprise's setup user, which will be the first owner in the enterprise. The setup user is only used to configure SAML single sign-on and SCIM provisioning integration for the enterprise. It will no longer have access to administer the enterprise account once SAML is successfully enabled.
|
||||
|
||||
The setup user's username is your enterprise's shortcode suffixed with `_admin`. After you log in to your setup user, you can get started by configuring SAML SSO for your enterprise. For more information, see "[Configuring SAML single sign-on for Enterprise Managed Users](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/configuring-saml-single-sign-on-for-enterprise-managed-users)."
|
||||
|
||||
{% note %}
|
||||
|
||||
{% data reusables.enterprise-accounts.emu-password-reset-session %}
|
||||
|
||||
{% endnote %}
|
||||
|
||||
## Authenticating as a {% data variables.product.prodname_managed_user %}
|
||||
|
||||
{% data variables.product.prodname_managed_users_caps %} must authenticate through their identity provider.
|
||||
|
||||
To authenticate, {% data variables.product.prodname_managed_users %} must visit their IdP application portal or **https://github.com/enterprises/ENTERPRISE_NAME**, replacing **ENTERPRISE_NAME** with your enterprise's name.
|
||||
|
||||
## Usernames and profile information
|
||||
|
||||
When your {% data variables.product.prodname_emu_enterprise %} is created, you will choose a short code that will be used as the suffix for your enterprise member's usernames. {% data reusables.enterprise-accounts.emu-shortcode %} The setup user who configures SAML SSO has a username in the format of **@<em>SHORT-CODE</em>_admin**.
|
||||
|
||||
When you provision a new user from your identity provider, the new {% data variables.product.prodname_managed_user %} will have a {% data variables.product.product_name %} username in the format of **@<em>IDP-USERNAME</em>_<em>SHORT-CODE</em>**. When using Azure Active Directory (Azure AD), _IDP-USERNAME_ is formed by normalizing the characters preceding the `@` character in the UPN (User Principal Name) provided by Azure AD. When using Okta, _IDP-USERNAME_ is the normalized username attribute provided by Okta.
|
||||
|
||||
The username of the new account provisioned on {% data variables.product.product_name %}, including underscore and short code, must not exceed 39 characters.
|
||||
|
||||
The profile name and email address of a {% data variables.product.prodname_managed_user %} is also provided by the IdP. {% data variables.product.prodname_managed_users_caps %} cannot change their profile name or email address on {% data variables.product.prodname_dotcom %}.
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
title: Auditing activity in your enterprise
|
||||
shortTitle: Auditing activity
|
||||
intro: 'You can audit the activity of the {% data variables.product.prodname_managed_users %} in your enterprise, viewing information about what actions were performed, by which user, and when they took place.'
|
||||
permissions: 'Enterprise owners can access the audit log.'
|
||||
product: '{% data reusables.gated-features.emus %}'
|
||||
versions:
|
||||
fpt: '*'
|
||||
topics:
|
||||
- Accounts
|
||||
- Enterprise
|
||||
---
|
||||
|
||||
## About the audit log
|
||||
|
||||
The audit log allows enterprise owners to quickly review or export the actions performed by both owners and members of your enterprise. Each audit log entry shows information about the event.
|
||||
|
||||
- The organization an action was performed in
|
||||
- The user who performed the action
|
||||
- Which repository an action was performed in
|
||||
- The action that was performed
|
||||
- Which country the action took place in
|
||||
- The date and time the action occurred
|
||||
|
||||
## Accessing the audit log
|
||||
|
||||
You can also access the audit log for your enterprise from the REST API. For more information, see "[GitHub Enterprise administration](/rest/reference/enterprise-admin#get-the-audit-log-for-an-enterprise)" in the API documentation.
|
||||
|
||||
{% data reusables.enterprise-accounts.access-enterprise %}
|
||||
{% data reusables.enterprise-accounts.settings-tab %}
|
||||
{% data reusables.enterprise-accounts.audit-log-tab %}
|
||||
1. Optionally, above the list of events, select the **Export Git Events** or **Export** drop-down menu and choose options for exporting events from the audit log.
|
||||

|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
title: Configuring SAML single sign-on for Enterprise Managed Users
|
||||
shortTitle: SAML for managed users
|
||||
intro: 'You can automatically manage access to your enterprise account on {% data variables.product.prodname_dotcom %} by configuring Security Assertion Markup Language (SAML) single sign-on (SSO).'
|
||||
product: '{% data reusables.gated-features.emus %}'
|
||||
versions:
|
||||
fpt: '*'
|
||||
topics:
|
||||
- Accounts
|
||||
- Enterprise
|
||||
---
|
||||
|
||||
## About SAML single sign-on for {% data variables.product.prodname_emus %}
|
||||
|
||||
With {% data variables.product.prodname_emus %}, your enterprise uses SAML SSO to authenticate all members. Instead of signing in to {% data variables.product.prodname_dotcom %} with a {% data variables.product.prodname_dotcom %} username and password, members of your enterprise will sign in through your IdP.
|
||||
|
||||
{% data variables.product.prodname_emus %} supports the following IdPs:
|
||||
|
||||
{% data reusables.enterprise-accounts.emu-supported-idps %}
|
||||
|
||||
After you configure SAML SSO, we recommend storing your recovery codes so you can recover access to your enterprise in the event that your identity provider is unavailable. For more information, see "[Saving your recovery codes](#saving-your-recovery-codes)."
|
||||
|
||||
## Configuring SAML single sign-on for {% data variables.product.prodname_emus %}
|
||||
|
||||
To configure SAML SSO for your {% data variables.product.prodname_emu_enterprise %}, you must configure an application on your IdP and then configure your enterprise on GitHub.com. After you configure SAML SSO, you can configure user provisioning.
|
||||
|
||||
To install and configure the {% data variables.product.prodname_emu_idp_application %} application on your IdP, you must have a tenant and administrative access on a supported IdP.
|
||||
|
||||
{% note %}
|
||||
|
||||
{% data reusables.enterprise-accounts.emu-password-reset-session %}
|
||||
|
||||
{% endnote %}
|
||||
|
||||
1. [Configuring your identity provider](#configuring-your-identity-provider)
|
||||
2. [Configuring your enterprise](#configuring-your-enterprise)
|
||||
3. [Enabling provisioning](#enabling-provisioning)
|
||||
|
||||
### Configuring your identity provider
|
||||
|
||||
To configure your IdP, follow the instructions they provide for configuring the {% data variables.product.prodname_emu_idp_application %} application on your IdP.
|
||||
|
||||
1. To install the {% data variables.product.prodname_emu_idp_application %} application, click the link for your IdP below:
|
||||
|
||||
- [{% data variables.product.prodname_emu_idp_application %} application on Azure Active Directory](https://azuremarketplace.microsoft.com/en-us/marketplace/apps/aad.githubenterprisemanageduser?tab=Overview)
|
||||
- [{% data variables.product.prodname_emu_idp_application %} application on Okta](https://www.okta.com/integrations/github-enterprise-managed-user)
|
||||
|
||||
1. To configure the {% data variables.product.prodname_emu_idp_application %} application and your IdP, click the link below and follow the instructions provided by your IdP:
|
||||
|
||||
- [Azure Active Directory tutorial for {% data variables.product.prodname_emus %}](https://docs.microsoft.com/en-us/azure/active-directory/saas-apps/github-enterprise-managed-user-tutorial)
|
||||
- [Okta documentation for {% data variables.product.prodname_emus %}](https://saml-doc.okta.com/SAML_Docs/How-to-Configure-SAML-2.0-for-GitHub-Enterprise-Managed-User.html)
|
||||
|
||||
1. So you can test and configure your enterprise, assign yourself or the user that will be configuring SAML SSO on {% data variables.product.prodname_dotcom %} to the {% data variables.product.prodname_emu_idp_application %} application on your IdP.
|
||||
|
||||
1. To enable you to continue configuring your enterprise on {% data variables.product.prodname_dotcom %}, locate and note the following information from the application you installed on your IdP:
|
||||
|
||||
| Value | Other names | Description |
|
||||
| :- | :- | :- |
|
||||
| IdP Sign-On URL | Login URL, IdP URL | Application's URL on your IdP |
|
||||
| IdP Identifier URL | Issuer | IdP's identifier to service providers for SAML authentication |
|
||||
| Signing certificate, Base64-encoded | Public certificate | Public certificate that IdP uses to sign authentication requests |
|
||||
|
||||
### Configuring your enterprise
|
||||
|
||||
After you install and configure the {% data variables.product.prodname_emu_idp_application %} application on your identity provider, you can configure your enterprise.
|
||||
|
||||
1. Sign into {% data variables.product.prodname_dotcom_the_website %} as the setup user for your new enterprise with the username **@<em>SHORT-CODE</em>_admin**.
|
||||
|
||||
{% data reusables.enterprise-accounts.access-enterprise %}
|
||||
{% data reusables.enterprise-accounts.settings-tab %}
|
||||
{% data reusables.enterprise-accounts.security-tab %}
|
||||
|
||||
1. Under "SAML single sign-on", select **Require SAML authentication**.
|
||||

|
||||
|
||||
1. Under **Sign on URL**, type the HTTPS endpoint of your IdP for single sign-on requests that you noted while configuring your IdP.
|
||||

|
||||
|
||||
1. Under **Issuer**, type your SAML issuer URL that you noted while configuring your IdP, to verify the authenticity of sent messages.
|
||||

|
||||
|
||||
1. Under **Public Certificate**, paste the certificate that you noted while configuring your IdP, to verify SAML responses.
|
||||

|
||||
|
||||
1. To verify the integrity of the requests from your SAML issuer, click {% octicon "pencil" aria-label="The edit icon" %}. Then, in the "Signature Method" and "Digest Method" drop-downs, choose the hashing algorithm used by your SAML issuer.
|
||||

|
||||
|
||||
1. Before enabling SAML SSO for your enterprise, to ensure that the information you've entered is correct, click **Test SAML configuration**. 
|
||||
|
||||
1. Click **Save**.
|
||||
|
||||
{% note %}
|
||||
|
||||
**Note:** When you require SAML SSO for your enterprise, the setup user will no longer have access to the enterprise but will remain signed in to GitHub. Only {% data variables.product.prodname_managed_users %} provisioned by your IdP will have access to the enterprise.
|
||||
|
||||
{% endnote %}
|
||||
|
||||
1. To ensure you can still access your enterprise in the event that your identity provider is ever unavailable in the future, click **Download**, **Print**, or **Copy** to save your recovery codes.
|
||||

|
||||
|
||||
### Enabling provisioning
|
||||
|
||||
After you enable SAML SSO, enable provisioning. For more information, see "[Configuring SCIM provisioning for enterprise managed users](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/configuring-scim-provisioning-for-enterprise-managed-users)."
|
||||
|
||||
## Saving your recovery codes
|
||||
|
||||
In the event that your identity provider is unavailable, you can use the setup user and a recovery code to sign in and access your enterprise. If you did not save your recovery codes when you configured SAML SSO, you can still access them from your enterprise's settings.
|
||||
|
||||
{% data reusables.enterprise-accounts.access-enterprise %}
|
||||
{% data reusables.enterprise-accounts.settings-tab %}
|
||||
{% data reusables.enterprise-accounts.security-tab %}
|
||||
|
||||
1. Under "Require SAML authentication", click **Save your recovery codes**.
|
||||

|
||||
|
||||
2. To save your recovery codes, click **Download**, **Print**, or **Copy**.
|
||||

|
||||
@@ -0,0 +1,80 @@
|
||||
---
|
||||
title: Configuring SCIM provisioning for Enterprise Managed Users with Okta
|
||||
shortTitle: Set up provisioning with Okta
|
||||
intro: 'You can provision new users and manage their membership of your enterprise and teams using Okta as your identity provider.'
|
||||
product: '{% data reusables.gated-features.emus %}'
|
||||
versions:
|
||||
fpt: '*'
|
||||
redirect_from:
|
||||
- /early-access/github/articles/configuring-provisioning-for-managed-users-with-okta
|
||||
topics:
|
||||
- Accounts
|
||||
- Enterprise
|
||||
---
|
||||
|
||||
## About provisioning with Okta
|
||||
|
||||
You can use {% data variables.product.prodname_emus %} with Okta as your identity provider to provision new accounts, manage enterprise membership, and manage team memberships for organizations in your enterprise. For more information about provisioning for {% data variables.product.prodname_emus %}, see "[Configuring SCIM provisioning for enterprise managed users](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/configuring-scim-provisioning-for-enterprise-managed-users)."
|
||||
|
||||
Before you can configure provisioning with Okta, you must configure SAML single-sign on. For more information, see "[Configuring SAML single sign-on for Enterprise Managed Users](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/configuring-saml-single-sign-on-for-enterprise-managed-users)."
|
||||
|
||||
To configure provisioning with Okta, you must set your enterprise's name in the {% data variables.product.prodname_emu_idp_application %} application and enter your setup user's personal access token. You can then start provisioning users in Okta.
|
||||
|
||||
## Supported features
|
||||
|
||||
{% data variables.product.prodname_emus %} supports many provisioning features in Okta.
|
||||
|
||||
| Feature | Description |
|
||||
| --- | --- |
|
||||
| Push New Users | Users that are assigned to the {% data variables.product.prodname_emu_idp_application %} application in Okta are automatically created in the enterprise on {% data variables.product.product_name %}. |
|
||||
| Push Profile Update | Updates made to the user's profile in Okta will be pushed to {% data variables.product.product_name %}. |
|
||||
| Push Groups | Groups in Okta that are assigned to the {% data variables.product.prodname_emu_idp_application %} application as Push Groups are automatically created in the enterprise on {% data variables.product.product_name %}. |
|
||||
| Push User Deactivation | Unassigning the user from the {% data variables.product.prodname_emu_idp_application %} application in Okta will disable the user on {% data variables.product.product_name %}. The user will not be able to sign in, but the user's information is maintained. |
|
||||
| Reactivate Users | Users in Okta whose Okta accounts are reactivated and who are assigned back to the {% data variables.product.prodname_emu_idp_application %} application will be enabled. |
|
||||
|
||||
{% note %}
|
||||
|
||||
**Note:** {% data variables.product.prodname_emus %} does not support modifications to usernames.
|
||||
|
||||
{% endnote %}
|
||||
|
||||
## Setting your enterprise name
|
||||
|
||||
After your {% data variables.product.prodname_emu_enterprise %} has been created, you can begin to configure provisioning by setting your enterprise name in Okta.
|
||||
|
||||
1. Navigate to your {% data variables.product.prodname_emu_idp_application %} application on Okta.
|
||||
1. Click the **Sign On** tab.
|
||||
1. To make changes, click **Edit**.
|
||||
1. Under "Advanced Sign-on Settings", in the "Enterprise Name" text box, type your enterprise name. For example, if you access your enterprise at `https://github.com/enterprises/octoinc`, your enterprise name would be "octoinc".
|
||||

|
||||
1. To save your enterprise name, click **Save**.
|
||||
|
||||
## Configuring provisioning
|
||||
|
||||
After setting your enterprise name, you can proceed to configure provisioning settings.
|
||||
|
||||
To configure provisioning, the setup user with the **@<em>SHORT-CODE</em>_admin** username will need to provide a personal access token with the **admin:enterprise** scope. For more information on creating a new token, see "[Creating a personal access token](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/configuring-scim-provisioning-for-enterprise-managed-users#creating-a-personal-access-token)."
|
||||
|
||||
1. Navigate to your {% data variables.product.prodname_emu_idp_application %} application on Okta.
|
||||
1. Click the **Provisioning** tab.
|
||||
1. In the settings menu, click **Integration**.
|
||||
1. To make changes, click **Edit**.
|
||||
1. Select **Enable API integration**.
|
||||
1. In the "API Token" field, enter the personal access token with the **admin:enterprise** scope belonging to the setup user.
|
||||

|
||||
1. Click **Test API Credentials**. If the test is successful, a verification message will appear at the top of the screen.
|
||||
1. To save the token, click **Save**.
|
||||
1. In the settings menu, click **To App**.
|
||||

|
||||
1. To the right of "Provisioning to App", to allow changes to be made, click **Edit**.
|
||||
1. Select **Enable** for **Create Users**, **Update User Attributes**, and **Deactivate Users**.
|
||||

|
||||
1. To finish configuring provisioning, click **Save**.
|
||||
|
||||
## Assigning users
|
||||
|
||||
After you have configured SAML SSO and provisioning, you will be able provision new users on {% data variables.product.prodname_dotcom_the_website %} by assigning users to the {% data variables.product.prodname_emu_idp_application %} application. You can also automatically manage organization membership by assigning groups to the application as push groups and connecting the push groups to teams in your organizations. For more information about managing teams, see "[Managing team memberships with identity provider groups](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/managing-team-memberships-with-identity-provider-groups)."
|
||||
|
||||
When assigning users, you can use the "Roles" attribute in the {% data variables.product.prodname_emu_idp_application %} application to set a user's role in your enterprise on {% data variables.product.product_name %}. For more information on roles, see "[Roles in an enterprise](/github/setting-up-and-managing-your-enterprise/managing-users-in-your-enterprise/roles-in-an-enterprise)."
|
||||
|
||||

|
||||