Skip to content

Commit 6c93c00

Browse files
authored
feat(editor): add support for multi-yml files e.g. products and versions (#4513)
1 parent 015ebf5 commit 6c93c00

33 files changed

+2205
-846
lines changed

packages/commons/docs-loader/src/editable-docs-loader.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,20 @@ interface DocsYmlError {
117117
interface GetDocsYmlSuccess {
118118
type: "ok";
119119
result: string;
120+
metadata: {
121+
path: string;
122+
defaultBranch: string;
123+
};
120124
}
121125

122126
export type GetDocsYmlResult = GetDocsYmlSuccess | DocsYmlError;
123127

124-
interface UpdateDocsYmlSuccess {
128+
interface GetDocsYmlAndReferencesSuccess {
125129
type: "ok";
130+
result: Map<string, string>;
126131
}
127132

128-
export type UpdateDocsYmlResult = UpdateDocsYmlSuccess | DocsYmlError;
133+
export type GetDocsYmlAndReferencesResult = GetDocsYmlAndReferencesSuccess | DocsYmlError;
129134

130135
export type FernConfigJsonErrors =
131136
| GetFernProjectErrors
@@ -157,18 +162,17 @@ export interface FernProject {
157162
}
158163

159164
/**
160-
* The GitLoader is used to get and update docs.yml from a remote git repository.
165+
* The GitLoader is used to get docs.yml and other files from a remote git repository.
161166
*/
162167
export interface GitLoader {
163168
getFernProjectBySite(owner: string, repo: string, site: string): Promise<GetFernProjectResult>;
164169
getDocsYml(owner: string, repo: string, site: string, ref?: string): Promise<GetDocsYmlResult>;
165-
updateDocsYml(
170+
getDocsYmlAndReferences(
166171
owner: string,
167172
repo: string,
168173
site: string,
169-
content: string,
170174
ref?: string
171-
): Promise<UpdateDocsYmlResult>;
175+
): Promise<GetDocsYmlAndReferencesResult>;
172176
getFernConfigJson(owner: string, repo: string, site: string): Promise<GetFernConfigJsonResult>;
173177
}
174178

packages/fdr-sdk/src/navigation/versions/latest/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ export * from "../../../client/generated/api/resources/navigation/resources/late
33
export * from "./getChildren";
44
export * from "./getPageId";
55
export * from "./isApiReferenceNode";
6+
export * from "./isExternalProductNode";
7+
export * from "./isInternalProductNode";
68
export * from "./isProductGroupNode";
79
export * from "./isProductNode";
810
export * from "./isSidebarRootNode";
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import type { ExternalProductNode, NavigationNode } from ".";
2+
3+
export function isExternalProductNode(node: NavigationNode): node is ExternalProductNode {
4+
return node.type === "productLink";
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import type { InternalProductNode, NavigationNode } from ".";
2+
3+
export function isInternalProductNode(node: NavigationNode): node is InternalProductNode {
4+
return node.type === "product";
5+
}

packages/fern-dashboard/src/app/[orgName]/(visual-editor)/editor/[docsUrl]/[branch]/[...slug]/@sidebar/CreatePageButton.tsx

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
"use client";
22

33
import type { SerializableFoundNode } from "@fern-docs/components/navigation";
4-
import { useNavigation } from "@fern-docs/components/navigation";
5-
64
import { DashboardTooltip } from "@/components/editor/DashboardTooltip";
75
import { Icon } from "@/components/icon/Icon";
86
import { Button } from "@/components/ui/button";
97
import { useEditingDisabled } from "@/hooks/useEditingDisabled";
108
import { useGitPrInfo } from "@/providers/GitPRContext";
11-
import { UI_MESSAGES } from "@/utils/messages";
129

1310
import { CreateClientPage } from "./CreateClientPage";
1411

@@ -20,24 +17,17 @@ interface CreatePageButtonProps {
2017
export function CreatePageButton({ baseFoundNode }: CreatePageButtonProps) {
2118
const { prStatus } = useGitPrInfo();
2219
const isEditingDisabled = useEditingDisabled();
23-
const navigation = useNavigation();
24-
25-
// LIMITATION: Page creation is not supported for multi-product or multi-version docs
26-
// These docs have separate docs.yml files for each product/version, and we would need to
27-
// determine which specific file to modify. This is a complex operation that's not yet supported.
28-
const canEditNavigation = navigation.canDirectlyEditDocsYmlNavigation;
2920

30-
const tooltipContent = !canEditNavigation
31-
? UI_MESSAGES.NAVIGATION_EDITS_NOT_SUPPORTED_MULTI_DOCS_YML
32-
: isEditingDisabled && prStatus === "merged"
33-
? "Cannot create page - PR has already been merged"
34-
: isEditingDisabled && prStatus === "closed"
35-
? "Cannot create page - PR has been closed"
36-
: undefined;
21+
const tooltipContent =
22+
isEditingDisabled && prStatus === "merged"
23+
? "Cannot create page - PR has already been merged"
24+
: isEditingDisabled && prStatus === "closed"
25+
? "Cannot create page - PR has been closed"
26+
: undefined;
3727

3828
return (
3929
<DashboardTooltip content={tooltipContent}>
40-
<CreateClientPage baseFoundNode={baseFoundNode} disabled={isEditingDisabled || !canEditNavigation}>
30+
<CreateClientPage baseFoundNode={baseFoundNode} disabled={isEditingDisabled}>
4131
<Button
4232
className="mb-2 flex w-full items-center justify-center gap-2 self-stretch rounded-lg border border-dashed border-[var(--grayscale-a6)] p-2 text-sm text-[var(--grayscale-a11)] hover:bg-[var(--grayscale-a3)] hover:text-[var(--grayscale-a12)]"
4333
variant="ghost"

packages/fern-dashboard/src/app/[orgName]/(visual-editor)/editor/[docsUrl]/[branch]/[...slug]/@sidebar/PageSidebar.tsx

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import type { DangerousTransmittableDocsLoaderData } from "@fern-api/docs-loader";
44
import { getIsSidebarFixed, getIsSingleOverviewPage } from "@fern-api/docs-utils";
5-
import type * as FernNavigation from "@fern-api/fdr-sdk/navigation";
5+
import * as FernNavigation from "@fern-api/fdr-sdk/navigation";
66
import {
77
type ClientPageDataDependencies,
88
type ResolvedPageData,
@@ -88,7 +88,11 @@ export default function PageSidebar({
8888
sidebarRootNodeId={found.sidebar?.id}
8989
tabId={found.currentTab?.id}
9090
productId={found.currentProduct?.productId}
91-
productSlug={found.currentProduct?.slug}
91+
productSlug={
92+
found.currentProduct && FernNavigation.isInternalProductNode(found.currentProduct)
93+
? found.currentProduct.slug
94+
: undefined
95+
}
9296
versionId={found.currentVersion?.versionId}
9397
versionSlug={found.currentVersion?.slug}
9498
variantId={found.currentVariant?.variantId}
@@ -114,12 +118,7 @@ export default function PageSidebar({
114118
renderOptions={{
115119
forceClientRender: true,
116120
wrapPageNode: (node, component) => (
117-
<DeletablePageNodeWrapper
118-
node={node}
119-
component={component}
120-
icon={undefined}
121-
depth={0}
122-
/>
121+
<DeletablePageNodeWrapper node={node} component={component} />
123122
),
124123
wrapSectionNode: (node, trigger) => <SidebarSectionWithMenu node={node} trigger={trigger} />
125124
}}

packages/fern-dashboard/src/app/[orgName]/(visual-editor)/editor/[docsUrl]/[branch]/[...slug]/PageNode.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22

3-
import type * as FernNavigation from "@fern-api/fdr-sdk/navigation";
3+
import * as FernNavigation from "@fern-api/fdr-sdk/navigation";
44
import {
55
type ClientPageDataDependencies,
66
type ResolvedPageData,
@@ -88,7 +88,11 @@ export default function PageNode(props: PageNode.Props) {
8888
sidebarRootNodeId={found.sidebar?.id}
8989
tabId={found.currentTab?.id}
9090
productId={found.currentProduct?.productId}
91-
productSlug={found.currentProduct?.slug}
91+
productSlug={
92+
found.currentProduct && FernNavigation.isInternalProductNode(found.currentProduct)
93+
? found.currentProduct.slug
94+
: undefined
95+
}
9296
versionId={found.currentVersion?.versionId}
9397
versionSlug={found.currentVersion?.slug}
9498
variantId={found.currentVariant?.variantId}

packages/fern-dashboard/src/app/[orgName]/(visual-editor)/editor/[docsUrl]/[branch]/layout.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,17 +62,17 @@ export default async function EditorLayout({
6262
const githubLoader = new GitHubLoader(githubUrl);
6363

6464
// Use the repo's default branch by passing preferDefaultBranch=true
65-
const docsYmlResult = await githubLoader.getDocsYml(
65+
const docsYmlAndReferences = await githubLoader.getDocsYmlAndReferences(
6666
sourceRepo.owner,
6767
sourceRepo.repo,
6868
docsUrl,
6969
branch, // fallback branch if default branch logic fails
7070
true // preferDefaultBranch = true
7171
);
72-
const initialDocsYmlContent = docsYmlResult.type === "ok" ? docsYmlResult.result : null;
72+
const latestDocsYmlAndReferences = docsYmlAndReferences.type === "ok" ? docsYmlAndReferences.result : null;
7373

74-
if (docsYmlResult.type !== "ok") {
75-
console.error(docsYmlResult.error);
74+
if (docsYmlAndReferences.type !== "ok") {
75+
console.error(docsYmlAndReferences.error);
7676
}
7777

7878
return (
@@ -93,7 +93,7 @@ export default async function EditorLayout({
9393
branchName={branch}
9494
orgName={orgName}
9595
docsUrl={docsUrl}
96-
initialDocsYmlContent={initialDocsYmlContent}
96+
latestDocsYmlAndReferences={latestDocsYmlAndReferences}
9797
>
9898
<CurrentPageProvider>
9999
<ClientMDXProvider>

packages/fern-dashboard/src/app/services/dal/github/createBranchIfNotExists.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ export default async function createBranchIfNotExists(request: {
105105
response
106106
};
107107
} catch (error) {
108+
console.error("[createBranchIfNotExists] Failed to create branch:", error);
108109
return {
109110
success: false,
110111
error: `Unknown error occurred: ${error}` // TODO: Add error message

0 commit comments

Comments
 (0)