Skip to content

Commit

Permalink
feature: API Playground (#329)
Browse files Browse the repository at this point in the history
  • Loading branch information
abvthecity authored Jan 19, 2024
1 parent 53031c4 commit 668264a
Show file tree
Hide file tree
Showing 114 changed files with 4,525 additions and 1,099 deletions.
983 changes: 499 additions & 484 deletions .pnp.cjs

Large diffs are not rendered by default.

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed .yarn/cache/dom4-npm-2.1.6-c189e2d3c4-c15ad56afb.zip
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed .yarn/cache/gud-npm-1.0.0-9747ac46ec-3e2eb37cf7.zip
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"@babel/preset-env": "^7.19.1",
"@babel/preset-react": "^7.22.15",
"@babel/preset-typescript": "^7.18.6",
"@blueprintjs/eslint-plugin": "^2.1.2",
"@blueprintjs/eslint-plugin": "^6.1.0",
"@types/is-ci": "^3.0.4",
"@types/jest": "^29.5.11",
"@types/lodash-es": "4.17.12",
Expand Down
1 change: 1 addition & 0 deletions packages/commons/app-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from "./serialize-node";
export * from "./slug";
export * from "./theme/loadDocsBackgroundImage";
export * from "./theme/loadDocsTypography";
export * from "./titleCase";
92 changes: 75 additions & 17 deletions packages/commons/app-utils/src/resolver.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { APIV1Read, DocsV1Read } from "@fern-api/fdr-sdk";
import { APIV1Read, DocsV1Read, FdrAPI } from "@fern-api/fdr-sdk";
import { isNonNullish, visitDiscriminatedUnion } from "@fern-ui/core-utils";
import { last, noop, sortBy, startCase } from "lodash-es";
import title from "title";
import { SPECIAL_TOKENS } from "./specialTokens";
import { last, noop, sortBy } from "lodash-es";
import { titleCase } from "./titleCase";

export function resolveNavigationItems(
navigationItems: DocsV1Read.NavigationItem[],
Expand Down Expand Up @@ -43,14 +42,21 @@ export function resolveNavigationItems(
hasMultipleBaseUrls: definition.hasMultipleBaseUrls,
slug: [...parentSlugs, api.urlSlug],
endpoints: definition.rootPackage.endpoints.map((endpoint) =>
resolveEndpointDefinition(endpoint, definition.types, definitionSlug)
resolveEndpointDefinition(
definition.id,
definition.id,
endpoint,
definition.types,
definitionSlug
)
),
webhooks: definition.rootPackage.webhooks.map((webhook) =>
resolveWebhookDefinition(webhook, definition.types, definitionSlug)
),
subpackages: definition.rootPackage.subpackages
.map((subpackageId) =>
resolveSubpackage(
api.api,
subpackageId,
definition.subpackages,
definition.types,
Expand Down Expand Up @@ -81,15 +87,8 @@ export function resolveNavigationItems(
return resolvedNavigationItems;
}

function formatSubpackageTitle(name: string) {
const titleCased = title(startCase(name), { special: SPECIAL_TOKENS });

// regex match "V 2", "V 4", etc. and replace it with "V2", "V4", etc.
const versionedTitle = titleCased.replace(/V\s(\d)/g, "V$1");
return versionedTitle;
}

function resolveSubpackage(
apiSectionId: FdrAPI.ApiDefinitionId,
subpackageId: APIV1Read.SubpackageId,
subpackagesMap: Record<string, APIV1Read.ApiDefinitionSubpackage>,
types: Record<string, APIV1Read.TypeDefinition>,
Expand All @@ -100,19 +99,22 @@ function resolveSubpackage(
return undefined;
}
const slug = [...parentSlugs, subpackage.urlSlug];
const endpoints = subpackage.endpoints.map((endpoint) => resolveEndpointDefinition(endpoint, types, slug));
const endpoints = subpackage.endpoints.map((endpoint) =>
resolveEndpointDefinition(apiSectionId, subpackageId, endpoint, types, slug)
);
const webhooks = subpackage.webhooks.map((webhook) => resolveWebhookDefinition(webhook, types, slug));
const subpackages = subpackage.subpackages
.map((subpackageId) => resolveSubpackage(subpackageId, subpackagesMap, types, slug))
.map((subpackageId) => resolveSubpackage(apiSectionId, subpackageId, subpackagesMap, types, slug))
.filter(isNonNullish);

if (endpoints.length === 0 && webhooks.length === 0 && subpackages.length === 0) {
return undefined;
}
return {
...subpackage,
title: formatSubpackageTitle(subpackage.name),
title: titleCase(subpackage.name),
type: "subpackage",
apiSectionId,
id: subpackageId,
slug,
endpoints,
Expand All @@ -123,6 +125,8 @@ function resolveSubpackage(
}

function resolveEndpointDefinition(
apiSectionId: FdrAPI.ApiDefinitionId,
apiPackageId: FdrAPI.ApiDefinitionId,
endpoint: APIV1Read.EndpointDefinition,
types: Record<string, APIV1Read.TypeDefinition>,
parentSlugs: string[]
Expand Down Expand Up @@ -154,6 +158,8 @@ function resolveEndpointDefinition(
return {
slug: [...parentSlugs, endpoint.urlSlug],
...endpoint,
apiSectionId,
apiPackageId,
title: endpoint.name != null ? endpoint.name : stringifyResolvedEndpointPathParts(path),
defaultEnvironment: endpoint.environments.find((environment) => environment.id === endpoint.defaultEnvironment),
path,
Expand Down Expand Up @@ -344,6 +350,7 @@ export type ResolvedNavigationItem =
| ResolvedNavigationItemPageGroup
| ResolvedNavigationItemApiSection
| ResolvedNavigationItemSection;

export interface ResolvedNavigationItemPageGroup {
type: "pageGroup";
pages: ResolvedPageMetadata[];
Expand All @@ -352,7 +359,6 @@ export interface ResolvedNavigationItemPageGroup {
export interface ResolvedPageMetadata {
id: DocsV1Read.PageId;
slug: string[];

title: string;
}

Expand All @@ -365,12 +371,22 @@ export interface ResolvedNavigationItemApiSection
slug: string[];
}

export function isResolvedNavigationItemApiSection(
item: ResolvedNavigationItem
): item is ResolvedNavigationItemApiSection {
return item.type === "apiSection";
}

export interface ResolvedNavigationItemSection extends Omit<DocsV1Read.DocsSection, "items" | "urlSlug"> {
type: "section";
items: ResolvedNavigationItem[];
slug: string[];
}

export function isResolvedNavigationItemSection(item: ResolvedNavigationItem): item is ResolvedNavigationItemSection {
return item.type === "section";
}

export interface ResolvedWithApiDefinition {
endpoints: ResolvedEndpointDefinition[];
webhooks: ResolvedWebhookDefinition[];
Expand All @@ -380,6 +396,7 @@ export interface ResolvedWithApiDefinition {

export interface ResolvedSubpackage extends APIV1Read.WithDescription, ResolvedWithApiDefinition {
type: "subpackage";
apiSectionId: FdrAPI.ApiDefinitionId;
id: APIV1Read.SubpackageId;
name: string;
title: string;
Expand All @@ -390,6 +407,8 @@ export type ResolvedApiDefinitionPackage = ResolvedNavigationItemApiSection | Re

export interface ResolvedEndpointDefinition extends APIV1Read.WithDescription {
id: APIV1Read.EndpointId;
apiSectionId: FdrAPI.ApiDefinitionId;
apiPackageId: FdrAPI.ApiDefinitionId | APIV1Read.SubpackageId;
slug: string[];
authed: boolean;
availability?: APIV1Read.Availability;
Expand Down Expand Up @@ -532,8 +551,47 @@ export type ResolvedTypeReference =

export type ResolvedHttpRequestBodyShape = APIV1Read.HttpRequestBodyShape.FileUpload | ResolvedTypeReference;

interface ResolvedHttpRequestBodyShapeVisitor<T> {
fileUpload: (shape: APIV1Read.HttpRequestBodyShape.FileUpload) => T;
typeReference: (shape: ResolvedTypeReference) => T;
}

export function visitResolvedHttpRequestBodyShape<T>(
shape: ResolvedHttpRequestBodyShape,
visitor: ResolvedHttpRequestBodyShapeVisitor<T>
): T {
if (shape.type === "fileUpload") {
return visitor.fileUpload(shape);
} else {
return visitor.typeReference(shape);
}
}

export type ResolvedHttpResponseBodyShape =
| APIV1Read.HttpResponseBodyShape.FileDownload
| APIV1Read.HttpResponseBodyShape.StreamingText
| APIV1Read.HttpResponseBodyShape.StreamCondition
| ResolvedTypeReference;

interface ResolvedHttpResponseBodyShapeVisitor<T> {
fileDownload: (shape: APIV1Read.HttpResponseBodyShape.FileDownload) => T;
streamingText: (shape: APIV1Read.HttpResponseBodyShape.StreamingText) => T;
streamCondition: (shape: APIV1Read.HttpResponseBodyShape.StreamCondition) => T;
typeReference: (shape: ResolvedTypeReference) => T;
}

export function visitResolvedHttpResponseBodyShape<T>(
shape: ResolvedHttpResponseBodyShape,
visitor: ResolvedHttpResponseBodyShapeVisitor<T>
): T {
switch (shape.type) {
case "fileDownload":
return visitor.fileDownload(shape);
case "streamingText":
return visitor.streamingText(shape);
case "streamCondition":
return visitor.streamCondition(shape);
default:
return visitor.typeReference(shape);
}
}
11 changes: 11 additions & 0 deletions packages/commons/app-utils/src/titleCase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { startCase } from "lodash-es";
import title from "title";
import { SPECIAL_TOKENS } from "./specialTokens";

export function titleCase(name: string): string {
const titleCased = title(startCase(name), { special: SPECIAL_TOKENS });

// regex match "V 2", "V 4", etc. and replace it with "V2", "V4", etc.
const versionedTitle = titleCased.replace(/V\s(\d)/g, "V$1");
return versionedTitle;
}
4 changes: 2 additions & 2 deletions packages/commons/react/common-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
"depcheck": "depcheck"
},
"dependencies": {
"@blueprintjs/core": "^4.11.5",
"@blueprintjs/icons": "^4.4.0",
"@blueprintjs/core": "^5.8.1",
"@blueprintjs/icons": "^5.7.0",
"@fern-ui/loadable": "workspace:*",
"classnames": "^2.5.1",
"react": "^18.2.0",
Expand Down
1 change: 1 addition & 0 deletions packages/commons/react/react-commons/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ export { useKeyboardPress } from "./useKeyboardPress";
export { useLocalTextState, type LocalTextState } from "./useLocalTextState";
export { useMounted } from "./useMounted";
export { useNumericState } from "./useNumericState";
export { usePrevious } from "./usePrevious";
export { useTimeout } from "./useTimeout";
export { useWhyDidYouUpdate } from "./useWhyDidYouUpdate";
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useEffect } from "react";

type Arrow = "Up" | "Down" | "Right" | "Left";

type OtherKey = "Enter";
type OtherKey = "Enter" | "Escape";

export declare namespace useKeyboardPress {
export interface Args {
Expand Down
9 changes: 9 additions & 0 deletions packages/commons/react/react-commons/src/usePrevious.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { useEffect, useRef } from "react";

export function usePrevious<T>(value: T): T {
const ref = useRef<T>(value);
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
2 changes: 1 addition & 1 deletion packages/commons/react/split-view/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"depcheck": "depcheck"
},
"dependencies": {
"@blueprintjs/core": "^4.11.5",
"@blueprintjs/core": "^5.8.1",
"@fern-ui/core-utils": "workspace:*",
"@fern-ui/react-commons": "workspace:*",
"classnames": "^2.5.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/commons/react/toaster/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"depcheck": "depcheck"
},
"dependencies": {
"@blueprintjs/core": "^4.11.5",
"@blueprintjs/core": "^5.8.1",
"classnames": "^2.5.1",
"react": "^18.2.0",
"react-dom": "^18.2.0"
Expand Down
8 changes: 4 additions & 4 deletions packages/commons/react/toaster/src/toaster.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Intent, Position, Toaster, ToasterInstance, ToasterPosition, ToastProps } from "@blueprintjs/core";
import { Intent, OverlayToaster, Position, Toaster, ToasterPosition, ToastProps } from "@blueprintjs/core";
import classNames from "classnames";
import styles from "./toaster.module.scss";

const DEFAULT_POSITION = Position.TOP;

const TOASTERS: Partial<Record<ToasterPosition, ToasterInstance>> = {};
function getToaster(position: ToasterPosition): ToasterInstance {
return (TOASTERS[position] ??= Toaster.create({ position }));
const TOASTERS: Partial<Record<ToasterPosition, Toaster>> = {};
function getToaster(position: ToasterPosition): Toaster {
return (TOASTERS[position] ??= OverlayToaster.create({ position }));
}

export interface ToastParams extends Pick<ToastProps, "className" | "intent" | "icon" | "action"> {
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/app/.depcheckrc.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{ "ignores": ["@types/jest", "@types/node", "vite", "@types/react", "@types/react"], "ignore-patterns": ["lib"] }
{ "ignores": ["@types/jest", "@types/node", "vite", "@types/react", "@types/react-dom"], "ignore-patterns": ["lib"] }
2 changes: 1 addition & 1 deletion packages/ui/app/.mrlint.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"private": true,
"rules": {
"depcheck": {
"ignores": ["@types/react"]
"ignores": ["@types/react-dom"]
}
}
}
13 changes: 8 additions & 5 deletions packages/ui/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,20 @@
"depcheck": "depcheck"
},
"dependencies": {
"@blueprintjs/core": "^4.11.5",
"@blueprintjs/icons": "^4.4.0",
"@blueprintjs/popover2": "^1.8.0",
"@blueprintjs/select": "^4.4.2",
"@blueprintjs/core": "^5.8.1",
"@blueprintjs/datetime": "^5.2.10",
"@blueprintjs/datetime2": "^2.2.9",
"@blueprintjs/icons": "^5.7.0",
"@blueprintjs/select": "^5.0.22",
"@fern-api/fdr-sdk": "0.44.0-1-geb2e930",
"@fern-ui/app-utils": "workspace:*",
"@fern-ui/core-utils": "workspace:*",
"@fern-ui/loadable": "workspace:*",
"@fern-ui/react-commons": "workspace:*",
"@fontsource/ibm-plex-mono": "^4.5.13",
"@fortawesome/fontawesome-svg-core": "^6.4.2",
"@fortawesome/react-fontawesome": "0.2.0",
"@headlessui/react": "^1.7.17",
"@headlessui/react": "^1.7.18",
"@react-hook/size": "^2.1.2",
"algoliasearch": "^4.22.1",
"classnames": "^2.5.1",
Expand Down Expand Up @@ -72,6 +74,7 @@
"@types/marked": "^5.0.0",
"@types/node": "^18.7.18",
"@types/react": "^18.0.20",
"@types/react-dom": "^18.2.18",
"@types/react-syntax-highlighter": "^15.5.11",
"@types/react-test-renderer": "^18.0.7",
"@types/tinycolor2": "^1.4.6",
Expand Down
3 changes: 2 additions & 1 deletion packages/ui/app/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { FocusStyleManager } from "@blueprintjs/core";
import "@blueprintjs/core/lib/css/blueprint.css";
import "@blueprintjs/datetime/lib/css/blueprint-datetime.css";
import "@blueprintjs/datetime2/lib/css/blueprint-datetime2.css";
import "@blueprintjs/icons/lib/css/blueprint-icons.css";
import "@blueprintjs/popover2/lib/css/blueprint-popover2.css";
import "@blueprintjs/select/lib/css/blueprint-select.css";
import { DocsV2Read } from "@fern-api/fdr-sdk";
import type { ResolvedPath } from "@fern-ui/app-utils";
Expand Down
6 changes: 6 additions & 0 deletions packages/ui/app/src/analytics/posthog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,9 @@ export function resetPosthog(): void {
posthog.reset();
});
}

export function capturePosthogEvent(eventName: string, properties?: Record<string, unknown>): void {
safeAccessPosthog(() => {
posthog.capture(eventName, properties);
});
}
18 changes: 0 additions & 18 deletions packages/ui/app/src/api-context/ApiDefinitionContext.ts

This file was deleted.

Loading

1 comment on commit 668264a

@vercel
Copy link

@vercel vercel bot commented on 668264a Jan 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

fern-dev – ./packages/ui/fe-bundle

fern-dev-git-main-buildwithfern.vercel.app
app-dev.buildwithfern.com
fern-dev-buildwithfern.vercel.app

Please sign in to comment.