Skip to content

Commit

Permalink
fix: prefer injected key in the api playground (#1848)
Browse files Browse the repository at this point in the history
  • Loading branch information
abvthecity authored Nov 23, 2024
1 parent 669b075 commit 20063fe
Show file tree
Hide file tree
Showing 18 changed files with 508 additions and 124 deletions.
3 changes: 0 additions & 3 deletions packages/parsers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@
"format:check": "prettier --check --ignore-unknown --ignore-path ../../shared/.prettierignore \"**\"",
"organize-imports": "organize-imports-cli tsconfig.json",
"depcheck": "depcheck",
"docs:dev": "NODE_OPTIONS='--inspect' next dev",
"docs:build": "next build",
"docs:start": "next start",
"lint": "pnpm lint:eslint && pnpm lint:style"
},
"dependencies": {
Expand Down
135 changes: 106 additions & 29 deletions packages/ui/app/src/atoms/playground.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
import * as FernNavigation from "@fern-api/fdr-sdk/navigation";
import { useEventCallback } from "@fern-ui/react-commons";
import { WritableAtom, atom, useAtom, useAtomValue, useSetAtom } from "jotai";
import { atomFamily, atomWithStorage, useAtomCallback } from "jotai/utils";
import { RESET, atomFamily, atomWithStorage, useAtomCallback } from "jotai/utils";
import { Dispatch, SetStateAction, useEffect } from "react";
import { useCallbackOne } from "use-memo-one";
import { selectHref } from "../hooks/useHref";
Expand Down Expand Up @@ -184,61 +184,138 @@ export const PLAYGROUND_AUTH_STATE_BEARER_TOKEN_ATOM = atom(
get(FERN_USER_ATOM)?.playground?.initial_state?.auth?.bearer_token ??
"",
}),
(_get, set, update: SetStateAction<PlaygroundAuthStateBearerToken>) => {
set(PLAYGROUND_AUTH_STATE_ATOM, (prev) => ({
...prev,
bearerAuth:
(_get, set, update: SetStateAction<PlaygroundAuthStateBearerToken> | typeof RESET) => {
set(PLAYGROUND_AUTH_STATE_ATOM, ({ bearerAuth: prevBearerAuth, ...rest }) => {
const nextBearerAuth =
typeof update === "function"
? update(prev.bearerAuth ?? PLAYGROUND_AUTH_STATE_BEARER_TOKEN_INITIAL)
: update,
}));
? update(prevBearerAuth ?? PLAYGROUND_AUTH_STATE_BEARER_TOKEN_INITIAL)
: update;

if (nextBearerAuth === RESET) {
return rest;
}

return { ...rest, bearerAuth: nextBearerAuth };
});
},
);

/**
* If an injected bearer token is provided, the input bearer token should be resettable if it's not empty.
*/
export const PLAYGROUND_AUTH_STATE_BEARER_TOKEN_IS_RESETTABLE_ATOM = atom((get) => {
const inputBearerAuth = get(PLAYGROUND_AUTH_STATE_BEARER_TOKEN_ATOM).token;
const injectedBearerAuth = get(FERN_USER_ATOM)?.playground?.initial_state?.auth?.bearer_token;
return injectedBearerAuth != null && inputBearerAuth !== injectedBearerAuth;
});

export const PLAYGROUND_AUTH_STATE_HEADER_ATOM = atom(
(get) => ({
headers: pascalCaseHeaderKeys({
...(get(PLAYGROUND_AUTH_STATE_ATOM).header?.headers ??
get(FERN_USER_ATOM)?.playground?.initial_state?.headers),
}),
}),
(_get, set, update: SetStateAction<PlaygroundAuthStateHeader>) => {
set(PLAYGROUND_AUTH_STATE_ATOM, (prev) => ({
...prev,
header: typeof update === "function" ? update(prev.header ?? PLAYGROUND_AUTH_STATE_HEADER_INITIAL) : update,
}));
(_get, set, update: SetStateAction<PlaygroundAuthStateHeader> | typeof RESET) => {
set(PLAYGROUND_AUTH_STATE_ATOM, ({ header: prevHeader, ...rest }) => {
const nextHeader =
typeof update === "function" ? update(prevHeader ?? PLAYGROUND_AUTH_STATE_HEADER_INITIAL) : update;

if (nextHeader === RESET) {
return rest;
}

return { ...rest, header: nextHeader };
});
},
);

export const PLAYGROUND_AUTH_STATE_BASIC_AUTH_ATOM = atom(
(get) => ({
username:
get(PLAYGROUND_AUTH_STATE_ATOM).basicAuth?.username ??
get(FERN_USER_ATOM)?.playground?.initial_state?.auth?.basic?.username ??
"",
get(FERN_USER_ATOM)?.playground?.initial_state?.auth?.basic?.username,
password:
get(PLAYGROUND_AUTH_STATE_ATOM).basicAuth?.password ??
get(FERN_USER_ATOM)?.playground?.initial_state?.auth?.basic?.password ??
"",
get(FERN_USER_ATOM)?.playground?.initial_state?.auth?.basic?.password,
}),
(_get, set, update: SetStateAction<PlaygroundAuthStateBasicAuth>) => {
set(PLAYGROUND_AUTH_STATE_ATOM, (prev) => ({
...prev,
basicAuth:
(_get, set, update: SetStateAction<Partial<PlaygroundAuthStateBasicAuth>> | typeof RESET) => {
set(PLAYGROUND_AUTH_STATE_ATOM, (prev) => {
if (prev == null) {
return {};
}

const { basicAuth: prevBasicAuth, ...rest } = prev;

const nextBasicAuth =
typeof update === "function"
? update(prev.basicAuth ?? PLAYGROUND_AUTH_STATE_BASIC_AUTH_INITIAL)
: update,
}));
? update(prevBasicAuth ?? PLAYGROUND_AUTH_STATE_BASIC_AUTH_INITIAL)
: update;

if (nextBasicAuth === RESET) {
return rest;
}

return { ...rest, basicAuth: { username: "", password: "", ...prevBasicAuth, ...nextBasicAuth } };
});
},
);

export const PLAYGROUND_AUTH_STATE_BASIC_AUTH_USERNAME_ATOM = atom(
(get) => get(PLAYGROUND_AUTH_STATE_BASIC_AUTH_ATOM).username,
(_get, set, update: SetStateAction<string> | typeof RESET) => {
set(PLAYGROUND_AUTH_STATE_BASIC_AUTH_ATOM, ({ username: prevUsername, ...rest }) => {
const nextUsername = typeof update === "function" ? update(prevUsername ?? "") : update;

if (nextUsername === RESET) {
return rest;
}

return { ...rest, username: nextUsername };
});
},
);

export const PLAYGROUND_AUTH_STATE_BASIC_AUTH_PASSWORD_ATOM = atom(
(get) => get(PLAYGROUND_AUTH_STATE_BASIC_AUTH_ATOM).password,
(_get, set, update: SetStateAction<string> | typeof RESET) => {
set(PLAYGROUND_AUTH_STATE_BASIC_AUTH_ATOM, ({ password: prevPassword, ...rest }) => {
const nextPassword = typeof update === "function" ? update(prevPassword ?? "") : update;

if (nextPassword === RESET) {
return rest;
}

return { ...rest, password: nextPassword };
});
},
);

export const PLAYGROUND_AUTH_STATE_BASIC_AUTH_USERNAME_IS_RESETTABLE_ATOM = atom((get) => {
const inputBasicAuth = get(PLAYGROUND_AUTH_STATE_BASIC_AUTH_ATOM);
const injectedBasicAuth = get(FERN_USER_ATOM)?.playground?.initial_state?.auth?.basic;
return injectedBasicAuth != null && inputBasicAuth.username !== injectedBasicAuth.username;
});

export const PLAYGROUND_AUTH_STATE_BASIC_AUTH_PASSWORD_IS_RESETTABLE_ATOM = atom((get) => {
const inputBasicAuth = get(PLAYGROUND_AUTH_STATE_BASIC_AUTH_ATOM);
const injectedBasicAuth = get(FERN_USER_ATOM)?.playground?.initial_state?.auth?.basic;
return injectedBasicAuth != null && inputBasicAuth.password !== injectedBasicAuth.password;
});

export const PLAYGROUND_AUTH_STATE_OAUTH_ATOM = atom(
(get) => get(PLAYGROUND_AUTH_STATE_ATOM).oauth ?? PLAYGROUND_AUTH_STATE_OAUTH_INITIAL,
(_get, set, update: SetStateAction<PlaygroundAuthStateOAuth>) => {
set(PLAYGROUND_AUTH_STATE_ATOM, (prev) => ({
...prev,
oauth: typeof update === "function" ? update(prev.oauth ?? PLAYGROUND_AUTH_STATE_OAUTH_INITIAL) : update,
}));
(_get, set, update: SetStateAction<PlaygroundAuthStateOAuth> | typeof RESET) => {
set(PLAYGROUND_AUTH_STATE_ATOM, ({ oauth: prevOauth, ...rest }) => {
const nextOauth =
typeof update === "function" ? update(prevOauth ?? PLAYGROUND_AUTH_STATE_OAUTH_INITIAL) : update;

if (nextOauth === RESET) {
return rest;
}

return { ...rest, oauth: nextOauth };
});
},
);

Expand Down
11 changes: 7 additions & 4 deletions packages/ui/app/src/playground/PasswordInputGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { FernButton, FernInput, FernInputProps } from "@fern-ui/components";
import { useBooleanState } from "@fern-ui/react-commons";
import { Eye, Lock } from "iconoir-react";
import { FC } from "react";
import { forwardRef } from "react";

export const PasswordInputGroup: FC<FernInputProps> = ({ ref, ...props }) => {
export const PasswordInputGroup = forwardRef<HTMLInputElement, FernInputProps>((props, forwardedRef) => {
const showPassword = useBooleanState(false);
return (
<FernInput
ref={forwardedRef}
leftIcon={<Lock className="size-icon" />}
{...props}
type={showPassword.value ? "text" : "password"}
rightElement={
props.value != null && props.value.length > 0 ? (
typeof props.value === "string" && props.value.length > 0 ? (
<FernButton
variant="minimal"
icon={<Eye />}
Expand All @@ -25,4 +26,6 @@ export const PasswordInputGroup: FC<FernInputProps> = ({ ref, ...props }) => {
}
/>
);
};
});

PasswordInputGroup.displayName = "PasswordInputGroup";
37 changes: 21 additions & 16 deletions packages/ui/app/src/playground/auth/PlaygroundBasicAuthForm.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import type { APIV1Read } from "@fern-api/fdr-sdk/client/types";
import { FernInput } from "@fern-ui/components";
import { User } from "iconoir-react";
import { useAtom } from "jotai/react";
import { ReactElement, useCallback } from "react";
import { PLAYGROUND_AUTH_STATE_BASIC_AUTH_ATOM } from "../../atoms";
import { useAtom, useAtomValue } from "jotai/react";
import { RESET } from "jotai/utils";
import { ReactElement } from "react";
import {
PLAYGROUND_AUTH_STATE_BASIC_AUTH_PASSWORD_ATOM,
PLAYGROUND_AUTH_STATE_BASIC_AUTH_PASSWORD_IS_RESETTABLE_ATOM,
PLAYGROUND_AUTH_STATE_BASIC_AUTH_USERNAME_ATOM,
PLAYGROUND_AUTH_STATE_BASIC_AUTH_USERNAME_IS_RESETTABLE_ATOM,
} from "../../atoms";
import { PasswordInputGroup } from "../PasswordInputGroup";

export function PlaygroundBasicAuthForm({
Expand All @@ -13,15 +19,10 @@ export function PlaygroundBasicAuthForm({
basicAuth: APIV1Read.BasicAuth;
disabled?: boolean;
}): ReactElement {
const [value, setValue] = useAtom(PLAYGROUND_AUTH_STATE_BASIC_AUTH_ATOM);
const handleChangeUsername = useCallback(
(newValue: string) => setValue((prev) => ({ ...prev, username: newValue })),
[setValue],
);
const handleChangePassword = useCallback(
(newValue: string) => setValue((prev) => ({ ...prev, password: newValue })),
[setValue],
);
const [username, setUsername] = useAtom(PLAYGROUND_AUTH_STATE_BASIC_AUTH_USERNAME_ATOM);
const [password, setPassword] = useAtom(PLAYGROUND_AUTH_STATE_BASIC_AUTH_PASSWORD_ATOM);
const isUsernameResettable = useAtomValue(PLAYGROUND_AUTH_STATE_BASIC_AUTH_USERNAME_IS_RESETTABLE_ATOM);
const isPasswordResettable = useAtomValue(PLAYGROUND_AUTH_STATE_BASIC_AUTH_PASSWORD_IS_RESETTABLE_ATOM);
return (
<>
<li className="-mx-4 space-y-2 p-4">
Expand All @@ -30,11 +31,13 @@ export function PlaygroundBasicAuthForm({
</label>
<div>
<FernInput
onValueChange={handleChangeUsername}
value={value.username}
onValueChange={setUsername}
value={username}
leftIcon={<User className="size-icon" />}
rightElement={<span className="t-muted text-xs">{"string"}</span>}
disabled={disabled}
resettable={isUsernameResettable}
onClickReset={() => setUsername(RESET)}
/>
</div>
</li>
Expand All @@ -46,9 +49,11 @@ export function PlaygroundBasicAuthForm({

<div>
<PasswordInputGroup
onValueChange={handleChangePassword}
value={value.password}
onValueChange={setPassword}
value={password}
disabled={disabled}
resettable={isPasswordResettable}
onClickReset={() => setPassword(RESET)}
/>
</div>
</li>
Expand Down
16 changes: 11 additions & 5 deletions packages/ui/app/src/playground/auth/PlaygroundBearerAuthForm.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import type { APIV1Read } from "@fern-api/fdr-sdk/client/types";
import { useAtom } from "jotai/react";
import { ReactElement, useCallback } from "react";
import { PLAYGROUND_AUTH_STATE_BEARER_TOKEN_ATOM } from "../../atoms";
import { useAtom, useAtomValue } from "jotai/react";
import { RESET } from "jotai/utils";
import { ReactElement } from "react";
import {
PLAYGROUND_AUTH_STATE_BEARER_TOKEN_ATOM,
PLAYGROUND_AUTH_STATE_BEARER_TOKEN_IS_RESETTABLE_ATOM,
} from "../../atoms";
import { PasswordInputGroup } from "../PasswordInputGroup";

export function PlaygroundBearerAuthForm({
Expand All @@ -12,7 +16,7 @@ export function PlaygroundBearerAuthForm({
disabled?: boolean;
}): ReactElement {
const [value, setValue] = useAtom(PLAYGROUND_AUTH_STATE_BEARER_TOKEN_ATOM);
const handleChange = useCallback((newValue: string) => setValue({ token: newValue }), [setValue]);
const isBearerTokenResettable = useAtomValue(PLAYGROUND_AUTH_STATE_BEARER_TOKEN_IS_RESETTABLE_ATOM);

return (
<li className="-mx-4 space-y-2 p-4">
Expand All @@ -22,11 +26,13 @@ export function PlaygroundBearerAuthForm({

<div>
<PasswordInputGroup
onValueChange={handleChange}
onValueChange={(newValue) => setValue({ token: newValue })}
value={value.token}
autoComplete="off"
data-1p-ignore="true"
disabled={disabled}
resettable={isBearerTokenResettable}
onClickReset={() => setValue(RESET)}
/>
</div>
</li>
Expand Down
Loading

0 comments on commit 20063fe

Please sign in to comment.