Skip to main content
Glama
Arize-ai

@arizeai/phoenix-mcp

Official
by Arize-ai
PlaygroundCredentialsDropdown.tsx11 kB
import { Suspense, useState } from "react"; import { graphql, useLazyLoadQuery } from "react-relay"; import { css } from "@emotion/react"; import { Button, CredentialField, CredentialInput, Dialog, DialogTrigger, ExternalLink, Flex, Form, Heading, Icon, Icons, Label, Popover, Skeleton, Text, ToggleButton, ToggleButtonGroup, View, } from "@phoenix/components"; import { GenerativeProviderIcon } from "@phoenix/components/generative/GenerativeProviderIcon"; import { ProviderToCredentialsConfigMap } from "@phoenix/constants/generativeConstants"; import { useCredentialsContext } from "@phoenix/contexts/CredentialsContext"; import { usePlaygroundContext } from "@phoenix/contexts/PlaygroundContext"; import { getProviderName, isModelProvider, } from "@phoenix/utils/generativeUtils"; import type { PlaygroundCredentialsDropdownQuery } from "./__generated__/PlaygroundCredentialsDropdownQuery.graphql"; export function PlaygroundCredentialsDropdown() { const currentProviders = usePlaygroundContext((state) => Array.from( new Set(state.instances.map((instance) => instance.model.provider)) ) ); const isRunning = usePlaygroundContext((state) => state.instances.some((instance) => instance.activeRunId != null) ); const [credentialView, setCredentialView] = useState<"local" | "server">( "local" ); return ( <div css={css` .ac-dropdown-button { min-width: 0px; } `} > <DialogTrigger> <Button size="S" isDisabled={isRunning} trailingVisual={<Icon svg={<Icons.ChevronDown />} />} > API Keys </Button> <Popover style={{ width: "500px" }}> <Dialog> {({ close }) => ( <View padding="size-200"> <Form onSubmit={(e) => { e.preventDefault(); close(); }} > <Flex direction="row" justifyContent="space-between" alignItems="center" > <Heading level={2} weight="heavy"> API Keys </Heading> <ToggleButtonGroup selectedKeys={[credentialView]} size="S" aria-label="Credential Source" onSelectionChange={(v) => { if (v.size === 0) { return; } const view = v.keys().next().value; if (view === "local" || view === "server") { setCredentialView(view); } }} > <ToggleButton aria-label="Local" id="local"> Local </ToggleButton> <ToggleButton aria-label="Server" id="server"> Server </ToggleButton> </ToggleButtonGroup> </Flex> {credentialView === "local" ? ( <LocalCredentialsView providers={currentProviders} /> ) : ( <Suspense fallback={<ServerCredentialsSkeleton />}> <ServerCredentialsView providers={currentProviders} /> </Suspense> )} <View paddingTop="size-100"> <Flex direction="row" gap="size-100" width="100%" justifyContent="end" > <ExternalLink href="/settings/providers"> View all AI provider configurations </ExternalLink> </Flex> </View> </Form> </View> )} </Dialog> </Popover> </DialogTrigger> </div> ); } function ServerCredentialsSkeleton() { return ( <View paddingY="size-100"> <Skeleton width="100%" height={20} animation="wave" /> <View paddingTop="size-100"> <Flex direction="column" gap="size-100"> <View paddingY="size-50"> <Flex direction="row" gap="size-100" alignItems="center"> <Skeleton width={24} height={24} borderRadius="circle" /> <Skeleton width={120} height={20} animation="wave" /> </Flex> <View paddingTop="size-100"> <Flex direction="column" gap="size-50"> <Skeleton width="80%" height={16} animation="wave" /> <Skeleton width="70%" height={16} animation="wave" /> </Flex> </View> </View> </Flex> </View> </View> ); } function LocalCredentialsView({ providers }: { providers: ModelProvider[] }) { return ( <> <View paddingY="size-50"> <Text color="text-700" size="XS"> Local API keys are stored in your browser and are not shared with other users. </Text> </View> <Flex direction="column" gap="size-100"> {providers.map((provider) => { const providerHasNoCredentials = !ProviderToCredentialsConfigMap[provider].length; if (providerHasNoCredentials) { // Do not show the credential field return null; } return ( <View key={provider} paddingY="size-50"> <Flex direction="row" gap="size-100" alignItems="center"> <GenerativeProviderIcon provider={provider} /> <Heading level={3} weight="heavy"> {getProviderName(provider)} </Heading> </Flex> <View paddingBottom="size-100" paddingTop="size-100"> <ProviderCredentials provider={provider} /> </View> </View> ); })} </Flex> </> ); } function ServerCredentialsView({ providers }: { providers: ModelProvider[] }) { const data = useLazyLoadQuery<PlaygroundCredentialsDropdownQuery>( graphql` query PlaygroundCredentialsDropdownQuery { modelProviders { key credentialRequirements { envVarName isRequired } credentialsSet } } `, {}, { fetchPolicy: "network-only" } ); // Create a map of provider key to credentialsSet status const credentialsStatusMap = new Map<ModelProvider, boolean | undefined>(); data.modelProviders.forEach((provider) => { if (isModelProvider(provider.key)) { credentialsStatusMap.set(provider.key, provider.credentialsSet); } }); return ( <View paddingY="size-100"> <Text color="text-700" size="S"> Server-side API keys are configured via environment variables and will be available to all users. </Text> <View paddingTop="size-100"> <Flex direction="column" gap="size-100"> {providers.map((provider) => { const credentialsConfig = ProviderToCredentialsConfigMap[provider]; if (!credentialsConfig.length) { return null; } const credentialsSet = credentialsStatusMap.get(provider); return ( <View key={provider} paddingY="size-50"> <Flex direction="row" gap="size-100" alignItems="center" justifyContent="space-between" > <Flex direction="row" gap="size-100" alignItems="center"> <GenerativeProviderIcon provider={provider} /> <Heading level={3} weight="heavy"> {getProviderName(provider)} </Heading> </Flex> {credentialsSet ? ( <Flex direction="row" gap="size-50" alignItems="center"> <Text color="success" size="S"> Configured </Text> <Icon color="success" svg={<Icons.CheckmarkCircleOutline />} /> </Flex> ) : ( <Flex direction="row" gap="size-50" alignItems="center"> <Text color="text-700" size="S"> Not Configured </Text> <Icon svg={<Icons.MinusCircleOutline />} /> </Flex> )} </Flex> <View paddingTop="size-100"> <Flex direction="column" gap="size-50"> {credentialsConfig.map((credentialConfig) => ( <Text key={credentialConfig.envVarName} color="text-600" size="S" > • {credentialConfig.envVarName} {credentialConfig.isRequired && ( <Text color="text-700" weight="heavy"> {" "} (required) </Text> )} </Text> ))} </Flex> </View> </View> ); })} </Flex> </View> </View> ); } function ProviderCredentials({ provider }: { provider: ModelProvider }) { const setCredential = useCredentialsContext((state) => state.setCredential); const credentialsConfig = ProviderToCredentialsConfigMap[provider]; const credentials = useCredentialsContext((state) => state[provider]); const isRunning = usePlaygroundContext((state) => state.instances.some((instance) => instance.activeRunId != null) ); return ( <View> {credentialsConfig.map((credentialConfig) => ( <CredentialField size="S" key={credentialConfig.envVarName} isRequired={credentialConfig.isRequired} onChange={(value) => { setCredential({ provider, envVarName: credentialConfig.envVarName, value, }); }} value={credentials?.[credentialConfig.envVarName] ?? ""} isDisabled={isRunning} > <Label>{credentialConfig.envVarName}</Label> <CredentialInput /> <Text slot="description"> {`Alternatively, you can set the "${credentialConfig.envVarName}" environment variable on the server.`} </Text> </CredentialField> ))} </View> ); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Arize-ai/phoenix'

If you have feedback or need assistance with the MCP directory API, please join our Discord server