-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: code-split api playground auth form (#1794)
- Loading branch information
1 parent
5686077
commit 2277c31
Showing
22 changed files
with
733 additions
and
622 deletions.
There are no files selected for viewing
594 changes: 0 additions & 594 deletions
594
packages/ui/app/src/playground/PlaygroundAuthorizationForm.tsx
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
packages/ui/app/src/playground/auth/PlaygroundAuthorizationForm.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import type { APIV1Read } from "@fern-api/fdr-sdk/client/types"; | ||
import { visitDiscriminatedUnion } from "@fern-api/ui-core-utils"; | ||
import { FC, ReactElement } from "react"; | ||
import { PlaygroundBasicAuthForm } from "./PlaygroundBasicAuthForm"; | ||
import { PlaygroundBearerAuthForm } from "./PlaygroundBearerAuthForm"; | ||
import { PlaygroundHeaderAuthForm } from "./PlaygroundHeaderAuthForm"; | ||
import { PlaygroundOAuthForm } from "./PlaygroundOAuthForm"; | ||
|
||
interface PlaygroundAuthorizationFormProps { | ||
auth: APIV1Read.ApiAuth; | ||
closeContainer: () => void; | ||
disabled: boolean; | ||
} | ||
|
||
export const PlaygroundAuthorizationForm: FC<PlaygroundAuthorizationFormProps> = ({ | ||
auth, | ||
closeContainer, | ||
disabled, | ||
}) => { | ||
return ( | ||
<ul className="list-none px-4"> | ||
{visitDiscriminatedUnion(auth, "type")._visit<ReactElement | false>({ | ||
bearerAuth: (bearerAuth) => <PlaygroundBearerAuthForm bearerAuth={bearerAuth} disabled={disabled} />, | ||
basicAuth: (basicAuth) => <PlaygroundBasicAuthForm basicAuth={basicAuth} disabled={disabled} />, | ||
header: (header) => <PlaygroundHeaderAuthForm header={header} disabled={disabled} />, | ||
oAuth: (oAuth) => ( | ||
<PlaygroundOAuthForm oAuth={oAuth} closeContainer={closeContainer} disabled={disabled} /> | ||
), | ||
_other: () => false, | ||
})} | ||
</ul> | ||
); | ||
}; |
72 changes: 72 additions & 0 deletions
72
packages/ui/app/src/playground/auth/PlaygroundAuthorizationFormCard.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import type { APIV1Read } from "@fern-api/fdr-sdk/client/types"; | ||
import { FernButton, FernCollapse } from "@fern-ui/components"; | ||
import { useBooleanState } from "@fern-ui/react-commons"; | ||
import { useSetAtom } from "jotai/react"; | ||
import { ReactElement } from "react"; | ||
import { PLAYGROUND_AUTH_STATE_BEARER_TOKEN_ATOM } from "../../atoms"; | ||
import { useApiKeyInjectionConfig } from "../../services/useApiKeyInjectionConfig"; | ||
import { PlaygroundAuthorizationForm } from "./PlaygroundAuthorizationForm"; | ||
import { PlaygroundCardTriggerApiKeyInjected } from "./PlaygroundCardTriggerApiKeyInjected"; | ||
import { PlaygroundCardTriggerManual } from "./PlaygroundCardTriggerManual"; | ||
|
||
interface PlaygroundAuthorizationFormCardProps { | ||
auth: APIV1Read.ApiAuth; | ||
disabled: boolean; | ||
} | ||
export function PlaygroundAuthorizationFormCard({ | ||
auth, | ||
disabled, | ||
}: PlaygroundAuthorizationFormCardProps): ReactElement | null { | ||
const setBearerAuth = useSetAtom(PLAYGROUND_AUTH_STATE_BEARER_TOKEN_ATOM); | ||
const isOpen = useBooleanState(false); | ||
const apiKeyInjection = useApiKeyInjectionConfig(); | ||
const apiKey = apiKeyInjection.enabled && apiKeyInjection.authenticated ? apiKeyInjection.access_token : null; | ||
|
||
const handleResetBearerAuth = () => { | ||
setBearerAuth({ token: apiKey ?? "" }); | ||
}; | ||
|
||
return ( | ||
<div> | ||
{apiKeyInjection.enabled ? ( | ||
<PlaygroundCardTriggerApiKeyInjected | ||
auth={auth} | ||
config={apiKeyInjection} | ||
disabled={disabled} | ||
toggleOpen={isOpen.toggleValue} | ||
onClose={isOpen.setFalse} | ||
/> | ||
) : ( | ||
<PlaygroundCardTriggerManual | ||
auth={auth} | ||
disabled={disabled} | ||
isOpen={isOpen.value} | ||
toggleOpen={isOpen.toggleValue} | ||
/> | ||
)} | ||
|
||
<FernCollapse open={isOpen.value}> | ||
<div className="pt-4"> | ||
<div className="fern-dropdown max-h-full"> | ||
<PlaygroundAuthorizationForm auth={auth} closeContainer={isOpen.setFalse} disabled={disabled} /> | ||
|
||
<div className="flex justify-end p-4 pt-2 gap-2"> | ||
{auth.type !== "oAuth" && ( | ||
<FernButton text="Done" intent="primary" onClick={isOpen.setFalse} /> | ||
)} | ||
{apiKey != null && ( | ||
<FernButton | ||
text="Reset token to default" | ||
intent="none" | ||
onClick={handleResetBearerAuth} | ||
size="normal" | ||
variant="outlined" | ||
/> | ||
)} | ||
</div> | ||
</div> | ||
</div> | ||
</FernCollapse> | ||
</div> | ||
); | ||
} |
57 changes: 57 additions & 0 deletions
57
packages/ui/app/src/playground/auth/PlaygroundBasicAuthForm.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
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 { PasswordInputGroup } from "../PasswordInputGroup"; | ||
|
||
export function PlaygroundBasicAuthForm({ | ||
basicAuth, | ||
disabled, | ||
}: { | ||
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], | ||
); | ||
return ( | ||
<> | ||
<li className="-mx-4 space-y-2 p-4"> | ||
<label className="inline-flex flex-wrap items-baseline"> | ||
<span className="font-mono text-sm">{basicAuth.usernameName ?? "Username"}</span> | ||
</label> | ||
<div> | ||
<FernInput | ||
onValueChange={handleChangeUsername} | ||
value={value.username} | ||
leftIcon={<User className="size-icon" />} | ||
rightElement={<span className="t-muted text-xs">{"string"}</span>} | ||
disabled={disabled} | ||
/> | ||
</div> | ||
</li> | ||
|
||
<li className="-mx-4 space-y-2 p-4"> | ||
<label className="inline-flex flex-wrap items-baseline"> | ||
<span className="font-mono text-sm">{basicAuth.passwordName ?? "Password"}</span> | ||
</label> | ||
|
||
<div> | ||
<PasswordInputGroup | ||
onValueChange={handleChangePassword} | ||
value={value.password} | ||
disabled={disabled} | ||
/> | ||
</div> | ||
</li> | ||
</> | ||
); | ||
} |
34 changes: 34 additions & 0 deletions
34
packages/ui/app/src/playground/auth/PlaygroundBearerAuthForm.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
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 { PasswordInputGroup } from "../PasswordInputGroup"; | ||
|
||
export function PlaygroundBearerAuthForm({ | ||
bearerAuth, | ||
disabled, | ||
}: { | ||
bearerAuth: APIV1Read.BearerAuth; | ||
disabled?: boolean; | ||
}): ReactElement { | ||
const [value, setValue] = useAtom(PLAYGROUND_AUTH_STATE_BEARER_TOKEN_ATOM); | ||
const handleChange = useCallback((newValue: string) => setValue({ token: newValue }), [setValue]); | ||
|
||
return ( | ||
<li className="-mx-4 space-y-2 p-4"> | ||
<label className="inline-flex flex-wrap items-baseline"> | ||
<span className="font-mono text-sm">{bearerAuth.tokenName ?? "Bearer token"}</span> | ||
</label> | ||
|
||
<div> | ||
<PasswordInputGroup | ||
onValueChange={handleChange} | ||
value={value.token} | ||
autoComplete="off" | ||
data-1p-ignore="true" | ||
disabled={disabled} | ||
/> | ||
</div> | ||
</li> | ||
); | ||
} |
145 changes: 145 additions & 0 deletions
145
packages/ui/app/src/playground/auth/PlaygroundCardTriggerApiKeyInjected.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
import type { APIV1Read } from "@fern-api/fdr-sdk/client/types"; | ||
import { FernButton, FernCard } from "@fern-ui/components"; | ||
import { APIKeyInjectionConfigEnabled } from "@fern-ui/fern-docs-auth"; | ||
import { Key, User } from "iconoir-react"; | ||
import { useAtomValue, useSetAtom } from "jotai"; | ||
import { useSearchParams } from "next/navigation"; | ||
import { ReactElement, useEffect } from "react"; | ||
import urlJoin from "url-join"; | ||
import { PLAYGROUND_AUTH_STATE_ATOM, PLAYGROUND_AUTH_STATE_BEARER_TOKEN_ATOM } from "../../atoms"; | ||
import { useApiRoute } from "../../hooks/useApiRoute"; | ||
import { Callout } from "../../mdx/components/callout"; | ||
import { PlaygroundAuthorizationForm } from "./PlaygroundAuthorizationForm"; | ||
|
||
interface PlaygroundCardTriggerApiKeyInjectedProps { | ||
auth: APIV1Read.ApiAuth; | ||
config: APIKeyInjectionConfigEnabled; | ||
disabled: boolean; | ||
toggleOpen: () => void; | ||
onClose: () => void; | ||
} | ||
|
||
export function PlaygroundCardTriggerApiKeyInjected({ | ||
auth, | ||
config, | ||
disabled, | ||
toggleOpen, | ||
onClose, | ||
}: PlaygroundCardTriggerApiKeyInjectedProps): ReactElement | false { | ||
const searchParams = useSearchParams(); | ||
const error = searchParams.get("error"); | ||
const errorDescription = searchParams.get("error_description"); | ||
const authState = useAtomValue(PLAYGROUND_AUTH_STATE_ATOM); | ||
const logoutApiRoute = useApiRoute("/api/fern-docs/auth/logout"); | ||
|
||
const apiKey = config.authenticated ? config.access_token : null; | ||
const setBearerAuth = useSetAtom(PLAYGROUND_AUTH_STATE_BEARER_TOKEN_ATOM); | ||
|
||
// TODO change this to on-login | ||
useEffect(() => { | ||
if (apiKey != null) { | ||
setBearerAuth({ token: apiKey }); | ||
} | ||
}, [apiKey, setBearerAuth]); | ||
|
||
const handleResetBearerAuth = () => { | ||
setBearerAuth({ token: apiKey ?? "" }); | ||
}; | ||
|
||
const redirectOrOpenAuthForm = () => { | ||
if (!config.authenticated) { | ||
const url = new URL(config.authorizationUrl); | ||
const state = new URL(window.location.href); | ||
if (state.searchParams.has("error")) { | ||
state.searchParams.delete("error"); | ||
} | ||
if (state.searchParams.has("error_description")) { | ||
state.searchParams.delete("error_description"); | ||
} | ||
url.searchParams.set(config.returnToQueryParam, state.toString()); | ||
window.location.replace(url); | ||
} else { | ||
toggleOpen(); | ||
} | ||
}; | ||
|
||
if (apiKey != null) { | ||
return ( | ||
<FernCard className="rounded-xl p-4 shadow-sm mb-3" title="Login to send a real request"> | ||
<FernButton | ||
className="w-full text-left pointer-events-none" | ||
size="large" | ||
intent="success" | ||
variant="outlined" | ||
text="Successfully logged in" | ||
icon={<Key />} | ||
active={true} | ||
/> | ||
<div className="-mx-4"> | ||
<PlaygroundAuthorizationForm auth={auth} closeContainer={onClose} disabled={disabled} /> | ||
</div> | ||
{ | ||
<div className="flex justify-end gap-2"> | ||
{apiKey !== authState?.bearerAuth?.token && apiKey && ( | ||
<FernButton | ||
text="Reset token to default" | ||
intent="none" | ||
icon={<Key />} | ||
onClick={handleResetBearerAuth} | ||
size="normal" | ||
variant="outlined" | ||
/> | ||
)} | ||
<FernButton | ||
text="Logout" | ||
intent="none" | ||
onClick={() => { | ||
if (!config.authenticated) { | ||
return; | ||
} | ||
const url = new URL(urlJoin(window.location.origin, logoutApiRoute)); | ||
const returnTo = new URL(window.location.href); | ||
url.searchParams.set(config.returnToQueryParam, returnTo.toString()); | ||
fetch(url) | ||
.then(() => { | ||
window.location.reload(); | ||
}) | ||
.catch((error) => { | ||
// eslint-disable-next-line no-console | ||
console.error(error); | ||
}); | ||
}} | ||
size="normal" | ||
variant="outlined" | ||
/> | ||
</div> | ||
} | ||
</FernCard> | ||
); | ||
} | ||
|
||
return ( | ||
<FernCard className="rounded-xl p-4 shadow-sm mb-2"> | ||
{error && <Callout intent="error">{errorDescription ?? error}</Callout>} | ||
|
||
<h5 className="t-muted m-0">Login to send a real request</h5> | ||
<div className="flex justify-center my-5 gap-2"> | ||
<FernButton | ||
size="normal" | ||
intent="primary" | ||
text="Login" | ||
icon={<User />} | ||
onClick={redirectOrOpenAuthForm} | ||
/> | ||
<FernButton | ||
size="normal" | ||
intent="none" | ||
variant="outlined" | ||
icon={<Key />} | ||
text="Provide token manually" | ||
onClick={toggleOpen} | ||
/> | ||
</div> | ||
</FernCard> | ||
); | ||
} |
Oops, something went wrong.