Skip to content

Commit

Permalink
restored most functionality and fixed some visual bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
RohinBhargava committed Oct 3, 2024
1 parent 13a1382 commit 42ff098
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 44 deletions.
7 changes: 7 additions & 0 deletions packages/ui/app/src/api-reference/ApiEndpointPage.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useSetAtom } from "jotai";
import { ALL_ENVIRONMENTS_ATOM } from "../atoms/environment";
import { ApiPageContext } from "../contexts/api-page";
import type { ResolvedApiEndpoint, ResolvedTypeDefinition } from "../resolver/types";
import { BuiltWithFern } from "../sidebar/BuiltWithFern";
Expand All @@ -12,6 +14,11 @@ export declare namespace ApiEndpointPage {
}

export const ApiEndpointPage: React.FC<ApiEndpointPage.Props> = ({ item, showErrors, types }) => {
const setEnvironmentIds = useSetAtom(ALL_ENVIRONMENTS_ATOM);
if (item.type === "endpoint" || item.type === "websocket") {
setEnvironmentIds(item.environments.map((env) => env.id));
}

return (
<ApiPageContext.Provider value={true}>
<SingleApiPageContent item={item} showErrors={showErrors} types={types} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export const EndpointUrl = React.forwardRef<HTMLDivElement, PropsWithChildren<En
})}
>
{showEnvironment && (
<span className="inline-flex whitespace-nowrap max-sm:hidden">
<span className="whitespace-nowrap max-sm:hidden">
<MaybeEnvironmentDropdown
selectedEnvironment={selectedEnvironment}
urlTextStyle="t-muted"
Expand Down
25 changes: 7 additions & 18 deletions packages/ui/app/src/atoms/environment.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,13 @@
import type { APIV1Read } from "@fern-api/fdr-sdk";
import { atom, useAtomValue } from "jotai";
import { atom, useAtomValue, useSetAtom } from "jotai";
import { atomWithStorage } from "jotai/utils";
import { isEndpoint, isWebSocket } from "../resolver/types";
import { DEPRECATED_FLATTENED_APIS_ATOM } from "./apis";

// Capture all possible environments in a list, in useEffect at top level
export const ALL_ENVIRONMENTS_ATOM = atom((get) => {
const flatApis = get(DEPRECATED_FLATTENED_APIS_ATOM);
const allEnvironmentIds = new Set<string>();
Object.values(flatApis).forEach((api) => {
api.endpoints.forEach((endpoint) => {
if (isEndpoint(endpoint) || isWebSocket(endpoint)) {
endpoint.environments.forEach((environment: APIV1Read.Environment) => {
allEnvironmentIds.add(environment.id);
});
}
});
});
return Array.from(allEnvironmentIds);
});
export const ALL_ENVIRONMENTS_ATOM = atom<string[]>([]);

export const useSetAllEnvironments = (allEnvironmentIds: string[]): void => {
const setAllEnvironments = useSetAtom(ALL_ENVIRONMENTS_ATOM);
setAllEnvironments(allEnvironmentIds);
};

// Get or select an environment
export const SELECTED_ENVIRONMENT_ATOM = atomWithStorage<string | undefined>("selected-environment", undefined);
Expand Down
50 changes: 42 additions & 8 deletions packages/ui/app/src/components/MaybeEnvironmentDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export function MaybeEnvironmentDropdown({
const [selectedEnvironmentId, setSelectedEnvironmentId] = useAtom(SELECTED_ENVIRONMENT_ATOM);
const [playgroundEnvironment, setPlaygroundEnvironment] = useAtom(PLAYGROUND_ENVIRONMENT_ATOM);
const [inputValue, setInputValue] = useState<string | undefined>(undefined);
const [initialState, setInitialState] = useState<string | undefined>(undefined);

const environmentIds = environmentFilters
? environmentFilters.filter((environmentFilter) => allEnvironmentIds.includes(environmentFilter))
Expand All @@ -54,12 +55,16 @@ export function MaybeEnvironmentDropdown({
inputValue != null && inputValue !== "" && parse(inputValue).host != null && parse(inputValue).protocol != null;

const urlProtocol = url ? url.protocol : "";
const fullyQualifiedDomainAndBasePath = url ? (url.pathname !== "/" ? `${url.host}${url.pathname}` : url.host) : "";
const fullyQualifiedDomainAndBasePath = url
? url.pathname != null && url.pathname !== "/"
? `${url.host}${url.pathname}`
: url.host
: "";

return (
<>
{isEditingEnvironment.value ? (
<span key="url" className="whitespace-nowrap max-sm:hidden font-mono">
<span key="url" className="inline-flex whitespace-nowrap max-sm:hidden font-mono">
<FernInput
autoFocus={isEditingEnvironment.value}
size={inputValue?.length ?? 0}
Expand All @@ -68,7 +73,20 @@ export function MaybeEnvironmentDropdown({
onClick={(e) => {
e.stopPropagation();
}}
onBlur={isEditingEnvironment.setFalse}
onBlur={(e) => {
if (isValidInput) {
if (playgroundEnvironment) {
setInputValue(playgroundEnvironment);
}
isEditingEnvironment.setFalse();
} else {
e.preventDefault();
e.stopPropagation();
setInputValue(initialState);
setPlaygroundEnvironment(initialState);
isEditingEnvironment.setFalse();
}
}}
onValueChange={(value) => {
if (
value === "" ||
Expand All @@ -82,16 +100,18 @@ export function MaybeEnvironmentDropdown({
setPlaygroundEnvironment(value);
}
}}
onKeyDown={(e) => {
onKeyDownCapture={(e) => {
if (e.key === "Enter" && isValidInput) {
if (playgroundEnvironment) {
setInputValue(playgroundEnvironment);
}
isEditingEnvironment.setFalse();
} else if (e.key === "Escape") {
setInputValue(playgroundEnvironment ?? selectedEnvironment?.baseUrl);
isEditingEnvironment.setFalse();
e.preventDefault();
e.stopPropagation();
setInputValue(initialState);
setPlaygroundEnvironment(initialState);
isEditingEnvironment.setFalse();
}
}}
className={cn("p-0", isValidInput ? "" : "error", "h-auto", "flex flex-col")}
Expand Down Expand Up @@ -128,7 +148,14 @@ export function MaybeEnvironmentDropdown({
size={small ? "small" : "normal"}
variant="outlined"
mono={true}
onDoubleClick={editable ? isEditingEnvironment.setTrue : () => undefined}
onDoubleClick={
editable
? () => {
setInitialState(inputValue);
isEditingEnvironment.setTrue();
}
: () => undefined
}
/>
</FernDropdown>
) : (
Expand All @@ -141,7 +168,14 @@ export function MaybeEnvironmentDropdown({
small ? "text-xs" : "text-sm",
"hover:shadow-lg",
)}
onDoubleClick={isEditingEnvironment.setTrue}
onDoubleClick={
editable
? () => {
setInitialState(inputValue);
isEditingEnvironment.setTrue();
}
: () => undefined
}
>
{`${urlProtocol}//${fullyQualifiedDomainAndBasePath}`}
</span>
Expand Down
17 changes: 1 addition & 16 deletions packages/ui/app/src/playground/code-snippets/useSnippet.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,10 @@
import { EndpointDefinition } from "@fern-api/fdr-sdk/api-definition";
import { useMemo } from "react";
import { usePlaygroundBaseUrl } from "../utils/select-environment";
import { PlaygroundCodeSnippetResolver } from "./resolver";
import { useApiDefinition } from "./useApiDefinition";

export const resolveEnvironmentUrlInCodeSnippet = (
endpoint: EndpointDefinition,
replacementBaseUrl: string | undefined,
requestCodeSnippet: string,
): string => {
const urlToReplace = endpoint.environments?.find((env) => requestCodeSnippet.includes(env.baseUrl))?.baseUrl;
return urlToReplace && replacementBaseUrl
? requestCodeSnippet.replace(urlToReplace, replacementBaseUrl)
: requestCodeSnippet;
};

export function useSnippet(resolver: PlaygroundCodeSnippetResolver, lang: "curl" | "python" | "typescript"): string {
const apiDefinition = useApiDefinition(resolver.context.node.apiDefinitionId, resolver.isSnippetTemplatesEnabled);
const baseUrl = usePlaygroundBaseUrl(resolver.context.endpoint);

// Resolve the code snippet
const code = useMemo(() => resolver.resolve(lang, apiDefinition), [resolver, lang, apiDefinition]);
return resolveEnvironmentUrlInCodeSnippet(resolver.context.endpoint, baseUrl, code);
return useMemo(() => resolver.resolve(lang, apiDefinition), [resolver, lang, apiDefinition]);
}
2 changes: 1 addition & 1 deletion packages/ui/app/src/playground/utils/select-environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ export function useSelectedEnvironment(endpoint: WebSocketChannel | EndpointDefi
export function usePlaygroundBaseUrl(endpoint: WebSocketChannel | EndpointDefinition): string | undefined {
const environment = useSelectedEnvironment(endpoint);
const playgroundBaseUrl = usePlaygroundEnvironment();
return environment?.baseUrl ?? playgroundBaseUrl;
return playgroundBaseUrl ?? environment?.baseUrl;
}

0 comments on commit 42ff098

Please sign in to comment.