Permissions redesign (#48873)
This commit is contained in:
@@ -47,7 +47,7 @@ pages:
|
|||||||
miniToc: In this article
|
miniToc: In this article
|
||||||
all_enterprise_releases: All Enterprise Server releases
|
all_enterprise_releases: All Enterprise Server releases
|
||||||
about_versions: About versions
|
about_versions: About versions
|
||||||
permissions_statement: Who can use this feature
|
permissions_callout_title: Who can use this feature?
|
||||||
video_from_transcript: See video for this transcript
|
video_from_transcript: See video for this transcript
|
||||||
support:
|
support:
|
||||||
still_need_help: Still need help?
|
still_need_help: Still need help?
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { ArticleGridLayout } from 'src/frame/components/article/ArticleGridLayou
|
|||||||
import { MiniTocs } from 'src/frame/components/ui/MiniTocs'
|
import { MiniTocs } from 'src/frame/components/ui/MiniTocs'
|
||||||
import { useAutomatedPageContext } from 'src/automated-pipelines/components/AutomatedPageContext'
|
import { useAutomatedPageContext } from 'src/automated-pipelines/components/AutomatedPageContext'
|
||||||
import { ClientSideHighlight } from 'src/frame/components/ClientSideHighlight'
|
import { ClientSideHighlight } from 'src/frame/components/ClientSideHighlight'
|
||||||
import { Alert } from 'src/frame/components/ui/Alert'
|
|
||||||
import { Breadcrumbs } from 'src/frame/components/page-header/Breadcrumbs'
|
import { Breadcrumbs } from 'src/frame/components/page-header/Breadcrumbs'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -40,9 +39,7 @@ export const AutomatedPage = ({ children }: Props) => {
|
|||||||
</Lead>
|
</Lead>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{permissions && <PermissionsStatement permissions={permissions} />}
|
<PermissionsStatement permissions={permissions} product={product} />
|
||||||
|
|
||||||
{product && <Alert className="mb-4" html={product} />}
|
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
toc={miniTocItems.length > 1 && <MiniTocs miniTocItems={miniTocItems} />}
|
toc={miniTocItems.length > 1 && <MiniTocs miniTocItems={miniTocItems} />}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ children:
|
|||||||
- /for-playwright
|
- /for-playwright
|
||||||
- /html-short-title
|
- /html-short-title
|
||||||
- /page-with-callout
|
- /page-with-callout
|
||||||
|
- /page-with-permissions-and-product-callout
|
||||||
- /table-with-ifversions
|
- /table-with-ifversions
|
||||||
- /code-snippet-with-hashbang
|
- /code-snippet-with-hashbang
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
title: Page with permissions and product callout
|
||||||
|
shortTitle: Callout page
|
||||||
|
intro: A very short intro
|
||||||
|
permissions: This is a permission callout
|
||||||
|
product: '{% data reusables.gated-features.not-for-ghes %}'
|
||||||
|
versions:
|
||||||
|
fpt: '*'
|
||||||
|
ghes: '*'
|
||||||
|
ghec: '*'
|
||||||
|
---
|
||||||
|
|
||||||
|
## Heading
|
||||||
|
|
||||||
|
Note that this page uses the `product` and `permissions` frontmatter property. So it should
|
||||||
|
result in a call out box rendered with two messages. But only if the version is *not*
|
||||||
|
Enterprise Server.
|
||||||
@@ -47,7 +47,7 @@ pages:
|
|||||||
miniToc: In this article
|
miniToc: In this article
|
||||||
all_enterprise_releases: All Enterprise Server releases
|
all_enterprise_releases: All Enterprise Server releases
|
||||||
about_versions: About versions
|
about_versions: About versions
|
||||||
permissions_statement: Who can use this feature
|
permissions_callout_title: Who can use this feature?
|
||||||
video_from_transcript: See video for this transcript
|
video_from_transcript: See video for this transcript
|
||||||
support:
|
support:
|
||||||
still_need_help: Still need help?
|
still_need_help: Still need help?
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
import { getDOM } from '#src/tests/helpers/e2etest.js'
|
|
||||||
|
|
||||||
describe('alerts', () => {
|
|
||||||
test('article page', async () => {
|
|
||||||
const $ = await getDOM('/get-started/foo/page-with-callout')
|
|
||||||
const callout = $('[data-testid=alert] div')
|
|
||||||
expect(callout.html()).toBe('<p>Callout for HubGit Pages</p>')
|
|
||||||
})
|
|
||||||
|
|
||||||
test('callout disappears depend on Liquid inside it', async () => {
|
|
||||||
// This page has `product:` property which is a piece of Liquid
|
|
||||||
// which makes it so that the rendered output of that becomes
|
|
||||||
// an empty string.
|
|
||||||
// This test tests that alert is not rendered if its output
|
|
||||||
// "exits" but is empty.
|
|
||||||
const $ = await getDOM('/enterprise-server@latest/get-started/foo/page-with-callout')
|
|
||||||
const callout = $('[data-testid=alert]')
|
|
||||||
expect(callout.length).toBe(0)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('toc landing page', async () => {
|
|
||||||
const $ = await getDOM('/actions/category')
|
|
||||||
const callout = $('[data-testid=alert] div')
|
|
||||||
expect(callout.html()).toBe('<p>This is the callout text</p>')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -8,17 +8,6 @@ describe('markdown rendering', () => {
|
|||||||
expect(html).toMatch('<code>syntax</code>')
|
expect(html).toMatch('<code>syntax</code>')
|
||||||
expect(html).toMatch('<em>HubGit</em>')
|
expect(html).toMatch('<em>HubGit</em>')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('page with permission frontmatter', async () => {
|
|
||||||
const $ = await getDOM('/get-started/markdown/permissions')
|
|
||||||
const html = $('[data-testid="permissions-statement"]').html()
|
|
||||||
// part of the UI
|
|
||||||
expect(html).toMatch('Who can use this feature')
|
|
||||||
// Markdown
|
|
||||||
expect(html).toMatch('<strong>admin</strong>')
|
|
||||||
// Liquid
|
|
||||||
expect(html).toMatch('HubGit Pages site')
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('alerts', () => {
|
describe('alerts', () => {
|
||||||
|
|||||||
48
src/fixtures/tests/permissions-callout.js
Normal file
48
src/fixtures/tests/permissions-callout.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import { getDOM } from '#src/tests/helpers/e2etest.js'
|
||||||
|
|
||||||
|
describe('permission statements', () => {
|
||||||
|
test('article page product statement', async () => {
|
||||||
|
const $ = await getDOM('/get-started/foo/page-with-callout')
|
||||||
|
const callout = $('[data-testid=product-statement] div')
|
||||||
|
expect(callout.html()).toBe('<p>Callout for HubGit Pages</p>')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('callout disappears depend on Liquid inside it', async () => {
|
||||||
|
// This page has `product:` property which is a piece of Liquid
|
||||||
|
// which makes it so that the rendered output of that becomes
|
||||||
|
// an empty string.
|
||||||
|
// This test tests that alert is not rendered if its output
|
||||||
|
// "exits" but is empty.
|
||||||
|
const $ = await getDOM('/enterprise-server@latest/get-started/foo/page-with-callout')
|
||||||
|
const callout = $('[data-testid=product-statement]')
|
||||||
|
expect(callout.length).toBe(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('toc landing page', async () => {
|
||||||
|
const $ = await getDOM('/actions/category')
|
||||||
|
const callout = $('[data-testid=product-statement] div')
|
||||||
|
expect(callout.html()).toBe('<p>This is the callout text</p>')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('page with permission frontmatter', async () => {
|
||||||
|
const $ = await getDOM('/get-started/markdown/permissions')
|
||||||
|
const html = $('[data-testid=permissions-statement] div').html()
|
||||||
|
// Markdown
|
||||||
|
expect(html).toMatch('<strong>admin</strong>')
|
||||||
|
// Liquid
|
||||||
|
expect(html).toMatch('HubGit Pages site')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('page with permission frontmatter and product statement', async () => {
|
||||||
|
const $ = await getDOM('/get-started/foo/page-with-permissions-and-product-callout.md')
|
||||||
|
const html = $('[data-testid=permissions-callout] div').html()
|
||||||
|
// part of the UI
|
||||||
|
expect(html).toMatch('Who can use this feature')
|
||||||
|
|
||||||
|
const permission = $('[data-testid=permissions-statement] div')
|
||||||
|
expect(permission.html()).toBe('<p>This is a permission callout</p>')
|
||||||
|
|
||||||
|
const product = $('[data-testid=product-statement] div')
|
||||||
|
expect(product.html()).toBe('<p>Callout for HubGit Pages</p>')
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -25,7 +25,7 @@ export const ArticleGridLayout = ({
|
|||||||
<Box className={cx(styles.containerBox, className)}>
|
<Box className={cx(styles.containerBox, className)}>
|
||||||
{topper && <Box gridArea="topper">{topper}</Box>}
|
{topper && <Box gridArea="topper">{topper}</Box>}
|
||||||
{intro && (
|
{intro && (
|
||||||
<Box id="article-intro" gridArea="intro" className="f4">
|
<Box id="article-intro" gridArea="intro" className="f4 pb-4">
|
||||||
{intro}
|
{intro}
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import dynamic from 'next/dynamic'
|
|||||||
import cx from 'classnames'
|
import cx from 'classnames'
|
||||||
import { LinkExternalIcon } from '@primer/octicons-react'
|
import { LinkExternalIcon } from '@primer/octicons-react'
|
||||||
|
|
||||||
import { Alert } from 'src/frame/components/ui/Alert'
|
|
||||||
import { DefaultLayout } from 'src/frame/components/DefaultLayout'
|
import { DefaultLayout } from 'src/frame/components/DefaultLayout'
|
||||||
import { ArticleTitle } from 'src/frame/components/article/ArticleTitle'
|
import { ArticleTitle } from 'src/frame/components/article/ArticleTitle'
|
||||||
import { useArticleContext } from 'src/frame/components/context/ArticleContext'
|
import { useArticleContext } from 'src/frame/components/context/ArticleContext'
|
||||||
@@ -62,12 +61,10 @@ export const ArticlePage = () => {
|
|||||||
|
|
||||||
const introCalloutsProp = (
|
const introCalloutsProp = (
|
||||||
<>
|
<>
|
||||||
{permissions && <PermissionsStatement permissions={permissions} />}
|
<PermissionsStatement permissions={permissions} product={product} />
|
||||||
|
|
||||||
{includesPlatformSpecificContent && <PlatformPicker />}
|
{includesPlatformSpecificContent && <PlatformPicker />}
|
||||||
{includesToolSpecificContent && <ToolPicker />}
|
{includesToolSpecificContent && <ToolPicker />}
|
||||||
|
|
||||||
{product && <Alert className="mb-4" html={product} />}
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
.permissions_statement {
|
|
||||||
border-left: 0.25rem solid var(--color-border-muted);
|
|
||||||
}
|
|
||||||
@@ -1,22 +1,35 @@
|
|||||||
import cx from 'classnames'
|
import { Box } from '@primer/react'
|
||||||
|
import { PersonIcon, BriefcaseIcon } from '@primer/octicons-react'
|
||||||
|
|
||||||
import styles from './PermissionsStatement.module.scss'
|
|
||||||
import { useTranslation } from 'src/languages/components/useTranslation'
|
import { useTranslation } from 'src/languages/components/useTranslation'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
permissions: string
|
product?: string
|
||||||
|
permissions?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PermissionsStatement({ permissions }: Props) {
|
export function PermissionsStatement({ product, permissions }: Props) {
|
||||||
const { t } = useTranslation('pages')
|
const { t } = useTranslation('pages')
|
||||||
|
if (!permissions && !product) return null
|
||||||
return (
|
return (
|
||||||
<div
|
<Box sx={{ borderRadius: 10, borderStyle: 'solid', borderColor: 'border.default', p: 3 }}>
|
||||||
className={cx(styles.permissions_statement, 'pl-3 my-4')}
|
<div data-search="hide" data-testid="permissions-callout">
|
||||||
data-search="hide"
|
<div className="mb-3 d-inline-block">
|
||||||
data-testid="permissions-statement"
|
<h2 className="f4">{t('permissions_callout_title')}</h2>
|
||||||
>
|
</div>
|
||||||
<div className="text-bold pr-2">{t('permissions_statement')}</div>
|
{permissions && (
|
||||||
<div dangerouslySetInnerHTML={{ __html: permissions }} />
|
<div className="d-flex" data-testid="permissions-statement">
|
||||||
</div>
|
<PersonIcon className="mt-1" />
|
||||||
|
<div className="pl-2" dangerouslySetInnerHTML={{ __html: permissions }} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{product && (
|
||||||
|
<div className="d-flex" data-testid="product-statement">
|
||||||
|
<BriefcaseIcon className="mt-1" />
|
||||||
|
<div className="pl-2" dangerouslySetInnerHTML={{ __html: product }} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { ArticleTitle } from 'src/frame/components/article/ArticleTitle'
|
|||||||
import { MarkdownContent } from 'src/frame/components/ui/MarkdownContent'
|
import { MarkdownContent } from 'src/frame/components/ui/MarkdownContent'
|
||||||
import { ArticleList } from 'src/landings/components/ArticleList'
|
import { ArticleList } from 'src/landings/components/ArticleList'
|
||||||
import { ArticleGridLayout } from 'src/frame/components/article/ArticleGridLayout'
|
import { ArticleGridLayout } from 'src/frame/components/article/ArticleGridLayout'
|
||||||
import { Alert } from 'src/frame/components/ui/Alert'
|
import { PermissionsStatement } from 'src/frame/components/ui/PermissionsStatement'
|
||||||
import { Lead } from 'src/frame/components/ui/Lead'
|
import { Lead } from 'src/frame/components/ui/Lead'
|
||||||
import { LearningTrackNav } from 'src/learning-track/components/article/LearningTrackNav'
|
import { LearningTrackNav } from 'src/learning-track/components/article/LearningTrackNav'
|
||||||
import { ClientSideRedirects } from 'src/rest/components/ClientSideRedirects'
|
import { ClientSideRedirects } from 'src/rest/components/ClientSideRedirects'
|
||||||
@@ -46,7 +46,7 @@ export const TocLanding = () => {
|
|||||||
|
|
||||||
{intro && <Lead data-search="lead">{intro}</Lead>}
|
{intro && <Lead data-search="lead">{intro}</Lead>}
|
||||||
|
|
||||||
{productCallout && <Alert html={productCallout} />}
|
<PermissionsStatement product={productCallout} />
|
||||||
|
|
||||||
<div className="border-bottom border-xl-0 pb-4 mb-5 pb-xl-2 mb-xl-2" />
|
<div className="border-bottom border-xl-0 pb-4 mb-5 pb-xl-2 mb-xl-2" />
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export type StructuredContentT = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const RestReferencePage = ({ restOperations }: StructuredContentT) => {
|
export const RestReferencePage = ({ restOperations }: StructuredContentT) => {
|
||||||
const { title, intro, renderedPage, permissions } = useAutomatedPageContext()
|
const { title, intro, renderedPage, permissions, product } = useAutomatedPageContext()
|
||||||
|
|
||||||
// Scrollable code blocks in our REST API docs and elsewhere aren't accessible
|
// Scrollable code blocks in our REST API docs and elsewhere aren't accessible
|
||||||
// via keyboard navigation without setting tabindex="0". But we don't want to set
|
// via keyboard navigation without setting tabindex="0". But we don't want to set
|
||||||
@@ -54,7 +54,7 @@ export const RestReferencePage = ({ restOperations }: StructuredContentT) => {
|
|||||||
</Lead>
|
</Lead>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{permissions && <PermissionsStatement permissions={permissions} />}
|
<PermissionsStatement permissions={permissions} product={product} />
|
||||||
|
|
||||||
{renderedPage && <MarkdownContent className="pt-3 pb-4">{renderedPage}</MarkdownContent>}
|
{renderedPage && <MarkdownContent className="pt-3 pb-4">{renderedPage}</MarkdownContent>}
|
||||||
{restOperations.length > 0 && (
|
{restOperations.length > 0 && (
|
||||||
|
|||||||
Reference in New Issue
Block a user