Skip to content

Commit

Permalink
Merge branch 'ajiang/mark-authed' into ajiang/jwt-audiences
Browse files Browse the repository at this point in the history
  • Loading branch information
abvthecity authored Oct 10, 2024
2 parents 9f3c4ff + fd66e56 commit 729bfe0
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 71 deletions.
6 changes: 6 additions & 0 deletions packages/commons/fdr-utils/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export interface VersionSwitcherInfo {
index: number;
availability: FernNavigation.Availability | undefined;
pointsTo: FernNavigation.Slug | undefined;
hidden: boolean | undefined;
authed: boolean | undefined;
}

interface SidebarTabGroup {
Expand All @@ -22,6 +24,8 @@ interface SidebarTabGroup {
index: number;
slug: FernNavigation.Slug;
pointsTo: FernNavigation.Slug | undefined;
hidden: boolean | undefined;
authed: boolean | undefined;
}

interface SidebarTabLink {
Expand All @@ -38,6 +42,8 @@ interface SidebarTabChangelog {
icon: string | undefined;
index: number;
slug: FernNavigation.Slug;
hidden: boolean | undefined;
authed: boolean | undefined;
}

export type SidebarTab = SidebarTabGroup | SidebarTabLink | SidebarTabChangelog;
7 changes: 6 additions & 1 deletion packages/ui/app/src/header/HeaderTabs.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { RemoteFontAwesomeIcon } from "@fern-ui/components";
import { SidebarTab } from "@fern-ui/fdr-utils";
import clsx from "clsx";
import { Lock } from "iconoir-react";
import { useAtomValue } from "jotai";
import { ReactElement } from "react";
import { CURRENT_TAB_INDEX_ATOM, TABS_ATOM } from "../atoms";
Expand All @@ -22,13 +24,16 @@ export function HeaderTab({ tab }: { tab: SidebarTab }): ReactElement {
return (
<li className="fern-header-tabs-list-item">
<FernLink
className="fern-header-tab-button"
className={clsx("fern-header-tab-button", {
"opacity-50": tab.type !== "tabLink" && tab.hidden,
})}
href={useSidebarTabHref(tab)}
data-state={currentTabIndex === tab.index ? "active" : "inactive"}
>
<div className="flex min-w-0 items-center justify-start space-x-2">
{tab.icon && <RemoteFontAwesomeIcon icon={tab.icon} />}
<span className="truncate font-medium">{tab.title}</span>
{tab.type !== "tabLink" && tab.authed && <Lock className="size-4 self-center text-faded" />}
</div>
</FernLink>
</li>
Expand Down
6 changes: 4 additions & 2 deletions packages/ui/app/src/header/VersionDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FernButton } from "@fern-ui/components";
import { getVersionAvailabilityLabel } from "@fern-ui/fdr-utils";
import { NavArrowDown } from "iconoir-react";
import { Lock, NavArrowDown } from "iconoir-react";
import { useAtomValue } from "jotai";
import { CURRENT_VERSION_ID_ATOM, VERSIONS_ATOM } from "../atoms";
import { FernLinkDropdown } from "../components/FernLinkDropdown";
Expand All @@ -25,13 +25,15 @@ export const VersionDropdown: React.FC<VersionDropdown.Props> = () => {
<div className="flex max-w-32">
<FernLinkDropdown
value={currentVersionId}
options={versions.map(({ id, title, availability, slug, pointsTo }) => ({
options={versions.map(({ id, title, availability, slug, pointsTo, hidden, authed }) => ({
type: "value",
label: title,
helperText: availability != null ? getVersionAvailabilityLabel(availability) : undefined,
value: id,
disabled: availability == null,
href: toHref(pointsTo ?? slug),
icon: authed ? <Lock className="size-4 self-center text-faded" /> : undefined,
className: hidden ? "opacity-50" : undefined,
}))}
contentProps={{
"data-testid": "version-dropdown-content",
Expand Down
10 changes: 7 additions & 3 deletions packages/ui/app/src/sidebar/SidebarTabButton.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { RemoteFontAwesomeIcon } from "@fern-ui/components";
import { SidebarTab } from "@fern-ui/fdr-utils";
import cn from "clsx";
import cn, { clsx } from "clsx";
import { memo } from "react";
import { FernLink } from "../components/FernLink";
import { useSidebarTabHref } from "../hooks/useSidebarTabHref";
Expand All @@ -24,13 +24,17 @@ const UnmemoizedSidebarTabButton: React.FC<SidebarTabButton.Props> = ({ tab, sel
href={useSidebarTabHref(tab)}
data-state={selected ? "active" : "inactive"}
>
<div className="flex min-w-0 items-center justify-start space-x-4">
<div
className={clsx("flex min-w-0 items-center justify-start space-x-4", {
"opacity-50": tab.type !== "tabLink" && tab.hidden,
})}
>
<div className="min-w-fit">
<div className="flex size-6 items-center ring-1 shadow-sm ring-border-default justify-center rounded-md group-hover/tab-button:bg-tag-primary group-hover/tab-button:ring-accent/70 bg-card-surface group-data-[state=active]/tab-button:bg-accent group-data-[state=active]/tab-button:ring-0 group-hover/tab-button:group-data-[state=active]/tab-button:bg-accent">
<RemoteFontAwesomeIcon
className="size-4 bg-faded group-hover/tab-button:bg-accent group-data-[state=active]/tab-button:bg-background group-hover/tab-button:group-data-[state=active]/tab-button:bg-background"
// TODO: Should we validate that the icon is not undefined in sidebar mode
icon={tab.icon ?? "book-open"}
icon={tab.type !== "tabLink" && tab.authed ? "lock" : tab.icon ?? "book-open"}
/>
</div>
</div>
Expand Down
117 changes: 54 additions & 63 deletions packages/ui/docs-bundle/src/server/withInitialProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import type { AuthProps } from "./authProps";
import { handleLoadDocsError } from "./handleLoadDocsError";
import type { LoadWithUrlResponse } from "./loadWithUrl";
import { isTrailingSlashEnabled } from "./trailingSlash";
import { pruneNavigationPredicate, withPrunedSidebar } from "./withPrunedSidebar";
import { withVersionSwitcherInfo } from "./withVersionSwitcherInfo";

interface WithInitialProps {
Expand Down Expand Up @@ -163,13 +164,6 @@ export async function withInitialProps({
: undefined,
};

const versions = withVersionSwitcherInfo({
node: node.node,
parents: node.parents,
versions: node.versions,
slugMap: node.collector.slugMap,
});

const logoHref =
docs.definition.config.logoHref ??
(node.landingPage?.slug != null && !node.landingPage.hidden ? `/${node.landingPage.slug}` : undefined);
Expand Down Expand Up @@ -202,34 +196,56 @@ export async function withInitialProps({
}
}

const sidebar =
node.sidebar != null
? FernNavigation.Pruner.from(node.sidebar)
.keep((n) => {
// prune hidden nodes, unless it is the current node
if (FernNavigation.hasMetadata(n) && n.hidden) {
return n.id === node.node.id;
}

// prune authenticated pages
if (
FernNavigation.hasMetadata(n) &&
n.authed &&
auth == null &&
!featureFlags.isAuthenticatedPagesDiscoverable
) {
return false;
}

// prune nodes that are not pages and have no children (avoid pruning links)
if (!FernNavigation.isPage(n) && !FernNavigation.isLeaf(n)) {
return FernNavigation.getChildren(n).length > 0;
}

return true;
})
.get()
: undefined;
const pruneOpts = {
node: node.node,
isAuthenticated: auth != null,
isAuthenticatedPagesDiscoverable: featureFlags.isAuthenticatedPagesDiscoverable,
};

const versions = withVersionSwitcherInfo({
node: node.node,
parents: node.parents,
versions: node.versions.filter((version) => pruneNavigationPredicate(version, pruneOpts)),
slugMap: node.collector.slugMap,
});

const sidebar = withPrunedSidebar(node.sidebar, pruneOpts);

const tabs = node.tabs
.filter((tab) => pruneNavigationPredicate(tab, pruneOpts))
.map((tab, index) =>
visitDiscriminatedUnion(tab)._visit<SidebarTab>({
tab: (tab) => ({
type: "tabGroup",
title: tab.title,
icon: tab.icon,
index,
slug: tab.slug,
pointsTo: tab.pointsTo,
hidden: tab.hidden,
authed: tab.authed,
}),
link: (link) => ({
type: "tabLink",
title: link.title,
icon: link.icon,
index,
url: link.url,
}),
changelog: (changelog) => ({
type: "tabChangelog",
title: changelog.title,
icon: changelog.icon,
index,
slug: changelog.slug,
hidden: changelog.hidden,
authed: changelog.authed,
}),
}),
);

const currentTabIndex = node.currentTab == null ? undefined : node.tabs.indexOf(node.currentTab);
const currentVersionId = node.currentVersion?.versionId;

const props: ComponentProps<typeof DocsPage> = {
baseUrl: docs.baseUrl,
Expand All @@ -251,34 +267,9 @@ export async function withInitialProps({
}
: undefined,
navigation: {
currentTabIndex: node.currentTab == null ? undefined : node.tabs.indexOf(node.currentTab),
tabs: node.tabs.map((tab, index) =>
visitDiscriminatedUnion(tab)._visit<SidebarTab>({
tab: (tab) => ({
type: "tabGroup",
title: tab.title,
icon: tab.icon,
index,
slug: tab.slug,
pointsTo: tab.pointsTo,
}),
link: (link) => ({
type: "tabLink",
title: link.title,
icon: link.icon,
index,
url: link.url,
}),
changelog: (changelog) => ({
type: "tabChangelog",
title: changelog.title,
icon: changelog.icon,
index,
slug: changelog.slug,
}),
}),
),
currentVersionId: node.currentVersion?.versionId,
currentTabIndex,
tabs,
currentVersionId,
versions,
sidebar,
trailingSlash: isTrailingSlashEnabled(),
Expand Down
45 changes: 45 additions & 0 deletions packages/ui/docs-bundle/src/server/withPrunedSidebar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import * as FernNavigation from "@fern-api/fdr-sdk/navigation";

interface WithPrunedSidebarOpts {
node: FernNavigation.NavigationNode;
isAuthenticated: boolean;
isAuthenticatedPagesDiscoverable: boolean;
}

/**
* Note: at the stage of calling this function, the audiences should already been evaluated.
*/
export function pruneNavigationPredicate(
n: FernNavigation.NavigationNode,
{ node, isAuthenticated, isAuthenticatedPagesDiscoverable }: WithPrunedSidebarOpts,
): boolean {
// prune hidden nodes, unless it is the current node
if (FernNavigation.hasMetadata(n) && n.hidden) {
return n.id === node.id;
}

// prune authenticated pages (unless the isAuthenticatedPagesDiscoverable flag is turned on)
if (FernNavigation.hasMetadata(n) && n.authed && isAuthenticated && !isAuthenticatedPagesDiscoverable) {
return false;
}

// prune nodes that are not pages and have no children (avoid pruning links)
if (!FernNavigation.isPage(n) && !FernNavigation.isLeaf(n)) {
return FernNavigation.getChildren(n).length > 0;
}

return true;
}

export function withPrunedSidebar(
sidebar: FernNavigation.SidebarRootNode | undefined,
opts: WithPrunedSidebarOpts,
): FernNavigation.SidebarRootNode | undefined {
if (!sidebar) {
return sidebar;
}

return FernNavigation.Pruner.from(sidebar)
.keep((n) => pruneNavigationPredicate(n, opts))
.get();
}
8 changes: 6 additions & 2 deletions packages/ui/docs-bundle/src/server/withVersionSwitcherInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ export function withVersionSwitcherInfo({
pointsTo: node.slug,
index,
availability: version.availability,
};
hidden: version.hidden,
authed: version.authed,
} satisfies VersionSwitcherInfo;
}

const expectedSlugs = unversionedSlugs.map((slug) => FernNavigation.slugjoin(version.slug, slug));
Expand Down Expand Up @@ -105,7 +107,9 @@ export function withVersionSwitcherInfo({
pointsTo,
index,
availability: version.availability,
};
hidden: version.hidden,
authed: version.authed,
} satisfies VersionSwitcherInfo;
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ export async function getDocsPageProps(
pointsTo,
index,
availability: version.availability,
hidden: version.hidden,
authed: version.authed,
};
});

Expand Down Expand Up @@ -138,6 +140,8 @@ export async function getDocsPageProps(
index,
slug: tab.slug,
pointsTo: tab.pointsTo,
hidden: tab.hidden,
authed: tab.authed,
}),
link: (link) => ({
type: "tabLink",
Expand All @@ -152,6 +156,8 @@ export async function getDocsPageProps(
icon: changelog.icon,
index,
slug: changelog.slug,
hidden: changelog.hidden,
authed: changelog.authed,
}),
}),
),
Expand Down

0 comments on commit 729bfe0

Please sign in to comment.