diff --git a/components/Admonition/Admonition.tsx b/components/Admonition/Admonition.tsx index 7186bbdcdd..c8dbe236a5 100644 --- a/components/Admonition/Admonition.tsx +++ b/components/Admonition/Admonition.tsx @@ -1,6 +1,6 @@ import cn from "classnames"; import { useContext, useMemo } from "react"; -import { DocsContext, getScopes } from "layouts/DocsPage/context"; +import { DocsContext } from "layouts/DocsPage/context"; import styles from "./Admonition.module.css"; const capitalize = (text: string): string => @@ -12,7 +12,6 @@ export interface AdmonitionProps { type: (typeof types)[number]; title: string; children: React.ReactNode; - scopeOnly: boolean; scope?: string | string[]; } @@ -20,23 +19,12 @@ const Admonition = ({ type = "tip", title, children, - scopeOnly = false, scope, }: AdmonitionProps) => { const resolvedType = type && types.includes(type) ? type : "tip"; - const { scope: currentScope } = useContext(DocsContext); - const scopes = useMemo(() => getScopes(scope), [scope]); - const isInCurrentScope = scopes.includes(currentScope); - const isHidden = scopeOnly && !isInCurrentScope; return ( -
+
{title || capitalize(type)}
{children}
diff --git a/components/Details/Details.tsx b/components/Details/Details.tsx index 25f206cfb8..a0fa84a8ef 100644 --- a/components/Details/Details.tsx +++ b/components/Details/Details.tsx @@ -3,7 +3,7 @@ import { useContext, useEffect, useState, useMemo } from "react"; import { useRouter } from "next/router"; import HeadlessButton from "components/HeadlessButton"; import Icon from "components/Icon"; -import { DocsContext, getScopes } from "layouts/DocsPage/context"; +import { DocsContext } from "layouts/DocsPage/context"; import { getAnchor } from "utils/url"; import styles from "./Details.module.css"; @@ -19,54 +19,35 @@ export interface DetailsProps { scope?: string | string[]; title: string; opened?: boolean; - scopeOnly: boolean; min: string; children: React.ReactNode; } export const Details = ({ scope, - scopeOnly = false, opened = false, title, min, children, }: DetailsProps) => { const { - scope: currentScope, versions: { current, latest }, } = useContext(DocsContext); const router = useRouter(); - const scopes = useMemo(() => getScopes(scope), [scope]); const [isOpened, setIsOpened] = useState(opened); - const isInCurrentScope = scopes.includes(currentScope); const detailsId = title ? transformTitleToAnchor(title) : "title"; const anchorInPath = getAnchor(router.asPath); - useEffect(() => { - if (scopes.length) { - setIsOpened(isInCurrentScope); - } - }, [scopes, isInCurrentScope]); - useEffect(() => { if (anchorInPath === detailsId) { setIsOpened(true); } }, [anchorInPath, detailsId]); - const isCloudAndNotCurrent = scopes.includes("cloud") && current !== latest; - const isHiddenInCurrentScope = scopeOnly && !isInCurrentScope; - const isHidden = isCloudAndNotCurrent || isHiddenInCurrentScope; - return (
setIsOpened((value) => !value)} @@ -75,17 +56,8 @@ export const Details = ({
{title}
- {(scope || min) && ( + {min && (
- {scopes && ( -
- {scopes.map((scope) => ( -
- {scope} -
- ))} -
- )} {min &&
VERSION {min}+
}
)} diff --git a/components/Link/hooks.ts b/components/Link/hooks.ts index f881eb7992..44d6d5e6a9 100644 --- a/components/Link/hooks.ts +++ b/components/Link/hooks.ts @@ -9,7 +9,7 @@ import { isExternalLink, isLocalAssetFile, } from "utils/url"; -import { DocsContext, updateScopeInUrl } from "layouts/DocsPage/context"; +import { DocsContext } from "layouts/DocsPage/context"; /* * This hook should return current href with resolved rewrites @@ -35,8 +35,6 @@ export const useNormalizedHref = (href: string) => { ? href.substring(basePath.length) : href; - let scope: ScopeType = useContext(DocsContext).scope; - const { query } = splitPath(href); // This needs to be added because all strings of "/docs/" are being stripped down to @@ -46,15 +44,6 @@ export const useNormalizedHref = (href: string) => { return href; } - // If a valid scope is provided via query parameter, adjust the - // link to navigate to that scope. - if ( - query.hasOwnProperty("scope") && - scopeValues.includes(query.scope as ScopeType) - ) { - scope = query["scope"] as ScopeType; - } - if ( isHash(noBaseHref) || isExternalLink(noBaseHref) || @@ -65,7 +54,5 @@ export const useNormalizedHref = (href: string) => { const currentHref = normalizePath(asPath); - let fullHref = resolve(splitPath(currentHref).path, noBaseHref); - - return updateScopeInUrl(fullHref, scope); + return resolve(splitPath(currentHref).path, noBaseHref); }; diff --git a/components/Notice/Notice.tsx b/components/Notice/Notice.tsx index 04e21695c1..cfc24512d7 100644 --- a/components/Notice/Notice.tsx +++ b/components/Notice/Notice.tsx @@ -1,7 +1,5 @@ import { useMemo, useContext } from "react"; import Icon from "components/Icon"; -import { DocsContext, getScopes } from "layouts/DocsPage/context"; -import { ScopesType } from "layouts/DocsPage/types"; import cn from "classnames"; import styles from "./Notice.module.css"; @@ -21,7 +19,7 @@ export interface NoticeProps { children: React.ReactNode; className?: string; icon?: boolean; - scope?: ScopesType; + scope?: string; } const Notice = ({ @@ -34,17 +32,8 @@ const Notice = ({ }: NoticeProps) => { const type = baseType && types.includes(baseType) ? baseType : "tip"; const iconName = typeIcons[type]; - const { scope: currentScope } = useContext(DocsContext); - const scopes = useMemo(() => getScopes(scope), [scope]); - - const isHidden = scope && !scopes.includes(currentScope); - return ( -
+
{icon && }
{children}
diff --git a/components/ScopedBlock/ScopedBlock.tsx b/components/ScopedBlock/ScopedBlock.tsx deleted file mode 100644 index 4f91a82df9..0000000000 --- a/components/ScopedBlock/ScopedBlock.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { useMemo, useContext } from "react"; -import { DocsContext, getScopes } from "layouts/DocsPage/context"; - -interface ScopedBlockProps { - scope: string | string[]; - children: React.ReactNode; -} - -export const ScopedBlock = ({ scope, children }: ScopedBlockProps) => { - const { scope: currentScope } = useContext(DocsContext); - const scopes = useMemo(() => getScopes(scope), [scope]); - const isInCurrentScope = scopes.includes(currentScope); - - return isInCurrentScope ? <>{children} : null; -}; diff --git a/components/ScopedBlock/index.ts b/components/ScopedBlock/index.ts deleted file mode 100644 index b729fbf34b..0000000000 --- a/components/ScopedBlock/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { ScopedBlock as default } from "./ScopedBlock"; diff --git a/components/Tabs/Tabs.tsx b/components/Tabs/Tabs.tsx index a7c70fbd92..3d3c4be4a3 100644 --- a/components/Tabs/Tabs.tsx +++ b/components/Tabs/Tabs.tsx @@ -6,7 +6,7 @@ import { useMemo, } from "react"; import { Dropdown } from "components/Dropdown"; -import { DocsContext, getScopes } from "layouts/DocsPage/context"; +import { DocsContext } from "layouts/DocsPage/context"; import { TabLabelList } from "./TabLabel"; import { TabItemList } from "./TabItem"; import { DataTab, TabsInDropdowns, TabItemProps, TabsProps } from "./types"; @@ -46,7 +46,7 @@ import { TabContext } from "./TabContext"; ``` - + ```code # Checkout teleport-plugins $ git clone https://github.com/gravitational/teleport-plugins.git @@ -78,7 +78,6 @@ export const Tabs = ({ dropdownView, }: TabsProps) => { const { - scope, versions: { latest, current }, } = useContext(DocsContext); @@ -168,16 +167,6 @@ export const Tabs = ({ setCurrentTab(getSelectedTab(tabsMeta)); }, [tabsMeta, selectedDropdownOption]); - useEffect(() => { - const scopedTab = childTabs.find(({ props }) => - getScopes(props.scope).includes(scope) - ); - - if (scopedTab) { - setCurrentTab(scopedTab.props.label); - } - }, [scope, childTabs]); - const visibleTabs = dropdownVarsArr.filter((t) => t !== DEFAULT_DROPDOWN); const dropOptions = tabsMeta.map((item) => item.label); diff --git a/layouts/DocsPage/DocsPage.tsx b/layouts/DocsPage/DocsPage.tsx index 97309c815f..e4039cbd72 100644 --- a/layouts/DocsPage/DocsPage.tsx +++ b/layouts/DocsPage/DocsPage.tsx @@ -45,22 +45,14 @@ const DocsPage = ({ }: DocsPageProps) => { const route = useCurrentHref(); - const { setVersions, scope, setScope } = useContext(DocsContext); + const { setVersions } = useContext(DocsContext); const { current, latest, available } = versions; const getPath = useFindDestinationPath(versions); useEffect(() => { setVersions(versions); - - if ( - scopes[0] !== "" && - scopes[0] !== "noScope" && - !scopes.includes(scope) - ) { - setScope(scopes[0]); - } - }, [versions, setVersions, setScope, scopes, scope]); + }, [versions, setVersions]); const isSectionLayout = layout === "section"; const isTocVisible = (!layout || layout === "doc") && tableOfContents.length; diff --git a/layouts/DocsPage/Header.tsx b/layouts/DocsPage/Header.tsx index 46e5725f6b..46318db9c9 100644 --- a/layouts/DocsPage/Header.tsx +++ b/layouts/DocsPage/Header.tsx @@ -30,8 +30,6 @@ const DocHeader = ({ latest, scopes, }: DocHeaderProps) => { - const { scope } = useContext(DocsContext); - return (
@@ -53,7 +51,6 @@ const DocHeader = ({ {...versions} className={styles.versions} getNewVersionPath={getNewVersionPath} - disabled={scope === "cloud" || scope === "team"} latest={latest} /> )} diff --git a/layouts/DocsPage/Navigation.tsx b/layouts/DocsPage/Navigation.tsx index 4e750204fc..ac1ea084a3 100644 --- a/layouts/DocsPage/Navigation.tsx +++ b/layouts/DocsPage/Navigation.tsx @@ -5,7 +5,6 @@ import HeadlessButton from "components/HeadlessButton"; import Search from "components/Search"; import Icon from "components/Icon"; import Link, { useCurrentHref } from "components/Link"; -import { getScopeFromUrl } from "./context"; import { NavigationItem, NavigationCategory, @@ -63,7 +62,6 @@ const DocsNavigationItems = ({ }: DocsNavigationItemsProps) => { const router = useRouter(); const docPath = useCurrentHref().split(SCOPELESS_HREF_REGEX)[0]; - const urlScope = getScopeFromUrl(router.asPath); return ( <> diff --git a/layouts/DocsPage/Scopes.module.css b/layouts/DocsPage/Scopes.module.css index 78a5a49dbb..74632956f0 100644 --- a/layouts/DocsPage/Scopes.module.css +++ b/layouts/DocsPage/Scopes.module.css @@ -19,3 +19,51 @@ margin-left: var(--m-1); } } + +.label { + display: inline-flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + height: 32px; + padding: 0 var(--m-2); + font-size: var(--fs-text-sm); + font-weight: 600; + border-radius: var(--r-default); + transition: background-color var(--t-interaction), + border-color var(--t-interaction); + + &.variant-availablefor { + color: var(--color-black); + background-color: var(--color-white); + } + + &.variant-gray { + color: var(--color-gray); + background-color: var(--color-white); + } + + &.variant-green { + color: var(--color-green); + background-color: var(--color-white); + } + + &.variant-blue { + color: var(--color-light-blue); + background-color: var(--color-white); + } + + @media (--sm-scr) { + font-size: var(--fs-text-md); + } +} + +.icon { + width: 14px; + height: 14px; + margin-right: var(--m-0-5); +} + +.wrapper { + position: relative; +} diff --git a/layouts/DocsPage/Scopes.tsx b/layouts/DocsPage/Scopes.tsx index 6dce26a78b..83deaa3c8f 100644 --- a/layouts/DocsPage/Scopes.tsx +++ b/layouts/DocsPage/Scopes.tsx @@ -6,6 +6,7 @@ import type { ScopeType, ScopesInMeta } from "./types"; import type { IconName } from "components/Icon"; import type { RadioButtonVariant } from "components/RadioButton"; import styles from "./Scopes.module.css"; +import Icon from "components/Icon"; interface ScopeDescription { value: ScopeType; @@ -46,22 +47,19 @@ const SCOPE_DESCRIPTIONS: Record< interface ScopesItemProps { scopeFeatures: ScopeDescription; - currentScope: ScopeType; } -const ScopesItem = ({ scopeFeatures, currentScope }: ScopesItemProps) => { +const ScopesItem = ({ scopeFeatures }: ScopesItemProps) => { return (
  • - +
    + + {" "} + {scopeFeatures.title} + +
  • ); }; @@ -72,27 +70,22 @@ interface ScopesProps { } export const Scopes = ({ scopes, className }: ScopesProps) => { - const { scope, setScope } = useContext(DocsContext); - - const onChange = useCallback( - (event) => { - setScope(event.target.value); - }, - [setScope] - ); - if (scopes[0] === "noScope" || scopes[0] === "") return <>; const scopeItems = scopes?.map((item) => ( )); return ( -
      +
        +
      • + + Available for: + +
      • {scopeItems}
      ); diff --git a/layouts/DocsPage/components.tsx b/layouts/DocsPage/components.tsx index cd7ea91458..1e66feedb5 100644 --- a/layouts/DocsPage/components.tsx +++ b/layouts/DocsPage/components.tsx @@ -3,7 +3,6 @@ import Command, { CommandLine, CommandComment } from "components/Command"; import Icon from "components/Icon"; import InlineCode from "components/InlineCode"; import Notice from "components/Notice"; -import ScopedBlock from "components/ScopedBlock"; import Snippet from "components/Snippet"; import { Tabs, TabItem } from "components/Tabs"; import { @@ -70,7 +69,6 @@ export const components = { commandcomment: CommandComment, icon: Icon, inlinecode: InlineCode, - scopedblock: ScopedBlock, tabs: Tabs, tabitem: TabItem, tile: Tile, diff --git a/layouts/DocsPage/context.tsx b/layouts/DocsPage/context.tsx index a3ff6f745d..f4d84df741 100644 --- a/layouts/DocsPage/context.tsx +++ b/layouts/DocsPage/context.tsx @@ -3,48 +3,7 @@ import { createContext, useState, useEffect } from "react"; import { splitPath, buildPath } from "utils/url"; import { VersionsInfo, scopeValues, ScopeType } from "./types"; -export const getScopes = (scopes?: string | string[]): ScopeType[] => { - if (typeof scopes === "string") { - return scopes - .split(",") - .map((scope) => scope.trim()) - .filter((scope) => - scopeValues.includes(scope as ScopeType) - ) as ScopeType[]; - } else if (Array.isArray(scopes)) { - return scopes.filter((scope) => - scopeValues.includes(scope as ScopeType) - ) as ScopeType[]; - } else { - return []; - } -}; - -export const getScopeFromUrl = (asPath: string): ScopeType => { - const { query } = splitPath(asPath); - - const scope = query.scope as ScopeType; - - return scopeValues.includes(scope) ? scope : "oss"; -}; - -export const updateScopeInUrl = (asPath: string, scope: ScopeType): string => { - const urlParts = splitPath(asPath); - - if (scope === "oss") { - if (urlParts.query.scope) { - delete urlParts.query.scope; - } - } else { - urlParts.query.scope = scope; - } - - return buildPath(urlParts); -}; - export interface DocsContextProps { - scope: ScopeType; - setScope: (scope: ScopeType) => void; versions: VersionsInfo; setVersions: (version: VersionsInfo) => void; } @@ -56,8 +15,6 @@ const defaultVersions = { }; export const DocsContext = createContext({ - scope: "oss", - setScope: () => undefined, versions: defaultVersions, setVersions: () => undefined, }); @@ -72,9 +29,7 @@ export const DocsContextProvider = ({ children }: DocsContextProviderProps) => { ? router.asPath.split("/")[2] : ""; - const urlScope = getScopeFromUrl(router.asPath); const [ready, setReady] = useState(false); - const [scope, setScope] = useState("oss"); const [versions, setVersions] = useState({ ...defaultVersions, current, @@ -83,26 +38,13 @@ export const DocsContextProvider = ({ children }: DocsContextProviderProps) => { // We set these variables to prevent incosistency with ssr useEffect(() => { if (!ready) { - setScope(urlScope); setReady(true); - } else { - if (scope === "cloud" && versions.current !== versions.latest) { - router.replace("/?scope=cloud"); - } else if (scope !== urlScope) { - router.replace( - updateScopeInUrl(router.asPath, scope), - updateScopeInUrl(router.asPath, scope), - { shallow: true } - ); - } } - }, [scope, ready, urlScope, router, versions]); + }, [ready, router, versions]); return (