-
Notifications
You must be signed in to change notification settings - Fork 44.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(platform): Simplify Credentials UX #8524
base: dev
Are you sure you want to change the base?
Changes from 5 commits
0842f20
30fbba3
800b8e3
8fb652d
33ba822
3f54524
4d09e53
f64a0b4
f9a3993
e143754
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -91,14 +91,10 @@ export const CredentialsInput: FC<{ | |
useState<AbortController | null>(null); | ||
const [oAuthError, setOAuthError] = useState<string | null>(null); | ||
|
||
if (!credentials) { | ||
if (!credentials || credentials.isLoading) { | ||
return null; | ||
} | ||
|
||
if (credentials.isLoading) { | ||
return <div>Loading...</div>; | ||
} | ||
|
||
Comment on lines
-94
to
-101
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why this change? |
||
const { | ||
schema, | ||
provider, | ||
|
@@ -226,6 +222,7 @@ export const CredentialsInput: FC<{ | |
if (savedApiKeys.length === 0 && savedOAuthCredentials.length === 0) { | ||
return ( | ||
<> | ||
<span className="text-m green mb-0 text-gray-900">Credentials</span> | ||
<div className={cn("flex flex-row space-x-2", className)}> | ||
{supportsOAuth2 && ( | ||
<Button onClick={handleOAuthLogin}> | ||
|
@@ -246,6 +243,31 @@ export const CredentialsInput: FC<{ | |
)} | ||
</> | ||
); | ||
// Only one saved credential | ||
} else if ( | ||
savedApiKeys.length === 0 && | ||
savedOAuthCredentials.length === 1 && | ||
selectedCredentials === undefined | ||
) { | ||
if (selectedCredentials === undefined) { | ||
onSelectCredentials({ | ||
id: savedOAuthCredentials[0].id, | ||
type: "oauth2", | ||
provider, | ||
title: savedOAuthCredentials[0].title, | ||
}); | ||
} | ||
return null; | ||
} else if (savedApiKeys.length === 1 && savedOAuthCredentials.length === 0) { | ||
if (selectedCredentials === undefined) { | ||
onSelectCredentials({ | ||
id: savedApiKeys[0].id, | ||
type: "api_key", | ||
provider, | ||
title: savedApiKeys[0].title, | ||
}); | ||
} | ||
return null; | ||
Comment on lines
+259
to
+283
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the purpose of this? This whole chain of logic seems questionably necessary. |
||
} | ||
|
||
function handleValueChange(newValue: string) { | ||
|
@@ -263,7 +285,7 @@ export const CredentialsInput: FC<{ | |
onSelectCredentials({ | ||
id: selectedCreds.id, | ||
type: selectedCreds.type, | ||
provider: schema.credentials_provider, | ||
provider: provider, | ||
// title: customTitle, // TODO: add input for title | ||
}); | ||
} | ||
|
@@ -272,6 +294,7 @@ export const CredentialsInput: FC<{ | |
// Saved credentials exist | ||
return ( | ||
<> | ||
<span className="text-m green mb-0 text-gray-900">Credentials</span> | ||
<Select value={selectedCredentials?.id} onValueChange={handleValueChange}> | ||
<SelectTrigger> | ||
<SelectValue placeholder={schema.placeholder} /> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -96,16 +96,19 @@ export type CredentialsType = "api_key" | "oauth2"; | |
|
||
// --8<-- [start:BlockIOCredentialsSubSchema] | ||
export const PROVIDER_NAMES = { | ||
ANTHROPIC: "anthropic", | ||
D_ID: "d_id", | ||
DISCORD: "discord", | ||
GITHUB: "github", | ||
GOOGLE: "google", | ||
GOOGLE_MAPS: "google_maps", | ||
GROQ: "groq", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. probably need logos for these too There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (even if fallback) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
IDEOGRAM: "ideogram", | ||
JINA: "jina", | ||
LLM: "llm", | ||
MEDIUM: "medium", | ||
NOTION: "notion", | ||
OLLAMA: "ollama", | ||
OPENAI: "openai", | ||
OPENWEATHERMAP: "openweathermap", | ||
PINECONE: "pinecone", | ||
|
@@ -122,6 +125,8 @@ export type BlockIOCredentialsSubSchema = BlockIOSubSchemaMeta & { | |
credentials_provider: CredentialsProviderName; | ||
credentials_scopes?: string[]; | ||
credentials_types: Array<CredentialsType>; | ||
discriminator?: string; | ||
discriminator_mapping?: { [key: string]: CredentialsProviderName }; | ||
}; | ||
|
||
export type BlockIONullSubSchema = BlockIOSubSchemaMeta & { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -312,3 +312,48 @@ export function findNewlyAddedBlockCoordinates( | |
y: 0, | ||
}; | ||
} | ||
|
||
type ParsedKey = { key: string; index?: number }; | ||
|
||
export function parseKeys(key: string): ParsedKey[] { | ||
const splits = key.split(/_@_|_#_|_\$_|\./); | ||
const keys: ParsedKey[] = []; | ||
let currentKey: string | null = null; | ||
|
||
splits.forEach((split) => { | ||
const isInteger = /^\d+$/.test(split); | ||
if (!isInteger) { | ||
if (currentKey !== null) { | ||
keys.push({ key: currentKey }); | ||
} | ||
currentKey = split; | ||
} else { | ||
if (currentKey !== null) { | ||
keys.push({ key: currentKey, index: parseInt(split, 10) }); | ||
currentKey = null; | ||
} else { | ||
throw new Error("Invalid key format: array index without a key"); | ||
} | ||
} | ||
}); | ||
|
||
if (currentKey !== null) { | ||
keys.push({ key: currentKey }); | ||
} | ||
|
||
return keys; | ||
} | ||
Comment on lines
+318
to
+345
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should probably add security test for this lol There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree but this code is already in the codebase I just moved it! |
||
|
||
/** | ||
* Get the value of a nested key in an object, handles arrays and objects. | ||
*/ | ||
export function getValue(key: string, value: any) { | ||
const keys = parseKeys(key); | ||
return keys.reduce((acc, k) => { | ||
if (acc === undefined) return undefined; | ||
if (k.index !== undefined) { | ||
return Array.isArray(acc[k.key]) ? acc[k.key][k.index] : undefined; | ||
} | ||
return acc[k.key]; | ||
}, value); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
imo this needs to be a structure that shows the allowable providers, not its own provider. something like
valid_providers = ['openai', 'grok', 'anthropic']
and be used in conjunction with discriminator always to have one of the providers be selected