chore: show important keys for provider configuration (#7265)

This commit is contained in:
Lifei Zhou
2026-02-18 18:10:53 +11:00
committed by GitHub
parent cc51ec0941
commit 5dacfde2f3
29 changed files with 283 additions and 158 deletions
+147 -99
View File
@@ -21,6 +21,7 @@ use goose::config::{
};
use goose::model::ModelConfig;
use goose::posthog::{get_telemetry_choice, TELEMETRY_ENABLED_KEY};
use goose::providers::base::ConfigKey;
use goose::providers::provider_test::test_provider_configuration;
use goose::providers::{create, providers, retry_operation, RetryConfig};
use goose::session::SessionType;
@@ -541,6 +542,129 @@ fn try_store_secret(config: &Config, key_name: &str, value: String) -> anyhow::R
}
}
async fn configure_single_key(
config: &Config,
provider_name: &str,
display_name: &str,
key: &ConfigKey,
) -> anyhow::Result<bool> {
let from_env = std::env::var(&key.name).ok();
match from_env {
Some(env_value) => {
let _ = cliclack::log::info(format!("{} is set via environment variable", key.name));
if cliclack::confirm("Would you like to save this value to your keyring?")
.initial_value(true)
.interact()?
{
if key.secret {
if !try_store_secret(config, &key.name, env_value)? {
return Ok(false);
}
} else {
config.set_param(&key.name, &env_value)?;
}
let _ = cliclack::log::info(format!("Saved {} to {}", key.name, config.path()));
}
}
None => {
let existing: Result<String, _> = if key.secret {
config.get_secret(&key.name)
} else {
config.get_param(&key.name)
};
match existing {
Ok(_) => {
let _ = cliclack::log::info(format!("{} is already configured", key.name));
if cliclack::confirm("Would you like to update this value?").interact()? {
if key.oauth_flow {
handle_oauth_configuration(provider_name, &key.name).await?;
} else {
let value: String = if key.secret {
cliclack::password(format!("Enter new value for {}", key.name))
.mask('▪')
.interact()?
} else {
let mut input =
cliclack::input(format!("Enter new value for {}", key.name));
if key.default.is_some() {
input = input.default_input(&key.default.clone().unwrap());
}
input.interact()?
};
if key.secret {
if !try_store_secret(config, &key.name, value)? {
return Ok(false);
}
} else {
config.set_param(&key.name, &value)?;
}
}
}
}
Err(_) => {
if key.oauth_flow {
handle_oauth_configuration(provider_name, &key.name).await?;
} else if !key.required && key.secret {
if cliclack::confirm(format!(
"Would you like to set {}? (optional)",
key.name
))
.initial_value(true)
.interact()?
{
let value: String =
cliclack::password(format!("Enter value for {}", key.name))
.mask('▪')
.interact()?;
if !try_store_secret(config, &key.name, value)? {
return Ok(false);
}
}
} else {
let prompt = if key.required {
format!(
"Provider {} requires {}, please enter a value",
display_name, key.name
)
} else {
format!("Enter {} (optional, press Enter to skip)", key.name)
};
let value: String = if key.secret {
cliclack::password(&prompt).mask('▪').interact()?
} else {
let mut input = cliclack::input(&prompt);
if key.default.is_some() {
input = input.default_input(&key.default.clone().unwrap());
}
if !key.required {
input = input.required(false);
}
input.interact()?
};
if value.is_empty() {
return Ok(true);
}
if key.secret {
if !try_store_secret(config, &key.name, value)? {
return Ok(false);
}
} else {
config.set_param(&key.name, &value)?;
}
}
}
}
}
}
Ok(true)
}
pub async fn configure_provider_dialog() -> anyhow::Result<bool> {
// Get global config instance
let config = Config::global();
@@ -574,107 +698,31 @@ pub async fn configure_provider_dialog() -> anyhow::Result<bool> {
.find(|(p, _)| &p.name == provider_name)
.expect("Selected provider must exist in metadata");
// Configure required provider keys
for key in &provider_meta.config_keys {
if !key.required {
continue;
for key in provider_meta
.config_keys
.iter()
.filter(|k| k.primary || k.oauth_flow)
{
if !configure_single_key(config, provider_name, &provider_meta.display_name, key).await? {
return Ok(false);
}
}
// First check if the value is set via environment variable
let from_env = std::env::var(&key.name).ok();
match from_env {
Some(env_value) => {
let _ =
cliclack::log::info(format!("{} is set via environment variable", key.name));
if cliclack::confirm("Would you like to save this value to your keyring?")
.initial_value(true)
.interact()?
{
if key.secret {
if !try_store_secret(config, &key.name, env_value)? {
return Ok(false);
}
} else {
config.set_param(&key.name, &env_value)?;
}
let _ = cliclack::log::info(format!("Saved {} to {}", key.name, config.path()));
}
}
None => {
let existing: Result<String, _> = if key.secret {
config.get_secret(&key.name)
} else {
config.get_param(&key.name)
};
match existing {
Ok(_) => {
let _ = cliclack::log::info(format!("{} is already configured", key.name));
if cliclack::confirm("Would you like to update this value?").interact()? {
// Check if this key uses OAuth flow
if key.oauth_flow {
handle_oauth_configuration(provider_name, &key.name).await?;
} else {
// Non-OAuth key, use manual entry
let value: String = if key.secret {
cliclack::password(format!("Enter new value for {}", key.name))
.mask('▪')
.interact()?
} else {
let mut input = cliclack::input(format!(
"Enter new value for {}",
key.name
));
if key.default.is_some() {
input = input.default_input(&key.default.clone().unwrap());
}
input.interact()?
};
if key.secret {
if !try_store_secret(config, &key.name, value)? {
return Ok(false);
}
} else {
config.set_param(&key.name, &value)?;
}
}
}
}
Err(_) => {
if key.oauth_flow {
handle_oauth_configuration(provider_name, &key.name).await?;
} else {
// Non-OAuth key, use manual entry
let value: String = if key.secret {
cliclack::password(format!(
"Provider {} requires {}, please enter a value",
provider_meta.display_name, key.name
))
.mask('▪')
.interact()?
} else {
let mut input = cliclack::input(format!(
"Provider {} requires {}, please enter a value",
provider_meta.display_name, key.name
));
if key.default.is_some() {
input = input.default_input(&key.default.clone().unwrap());
}
input.interact()?
};
if key.secret {
if !try_store_secret(config, &key.name, value)? {
return Ok(false);
}
} else {
config.set_param(&key.name, &value)?;
}
}
}
}
let non_primary_keys: Vec<_> = provider_meta
.config_keys
.iter()
.filter(|k| !k.primary && !k.oauth_flow)
.collect();
if !non_primary_keys.is_empty()
&& cliclack::confirm("Would you like to configure advanced settings?")
.initial_value(false)
.interact()?
{
for key in non_primary_keys {
if !configure_single_key(config, provider_name, &provider_meta.display_name, key)
.await?
{
return Ok(false);
}
}
}
+2 -1
View File
@@ -153,12 +153,13 @@ impl ProviderDef for AnthropicProvider {
models,
ANTHROPIC_DOC_URL,
vec![
ConfigKey::new("ANTHROPIC_API_KEY", true, true, None),
ConfigKey::new("ANTHROPIC_API_KEY", true, true, None, true),
ConfigKey::new(
"ANTHROPIC_HOST",
true,
false,
Some("https://api.anthropic.com"),
false,
),
],
)
+10 -4
View File
@@ -55,10 +55,16 @@ impl ProviderDef for AzureProvider {
AZURE_OPENAI_KNOWN_MODELS.to_vec(),
AZURE_DOC_URL,
vec![
ConfigKey::new("AZURE_OPENAI_ENDPOINT", true, false, None),
ConfigKey::new("AZURE_OPENAI_DEPLOYMENT_NAME", true, false, None),
ConfigKey::new("AZURE_OPENAI_API_VERSION", true, false, Some("2024-10-21")),
ConfigKey::new("AZURE_OPENAI_API_KEY", false, true, Some("")),
ConfigKey::new("AZURE_OPENAI_ENDPOINT", true, false, None, true),
ConfigKey::new("AZURE_OPENAI_DEPLOYMENT_NAME", true, false, None, true),
ConfigKey::new(
"AZURE_OPENAI_API_VERSION",
true,
false,
Some("2024-10-21"),
false,
),
ConfigKey::new("AZURE_OPENAI_API_KEY", false, true, Some(""), true),
],
)
}
+22 -3
View File
@@ -205,27 +205,39 @@ pub struct ConfigKey {
/// Whether this key should be configured using OAuth device code flow
/// When true, the provider's configure_oauth() method will be called instead of prompting for manual input
pub oauth_flow: bool,
/// Whether this key should be shown prominently during provider setup
/// (onboarding, settings modal, CLI configure)
#[serde(default)]
pub primary: bool,
}
impl ConfigKey {
/// Create a new ConfigKey
pub fn new(name: &str, required: bool, secret: bool, default: Option<&str>) -> Self {
pub fn new(
name: &str,
required: bool,
secret: bool,
default: Option<&str>,
primary: bool,
) -> Self {
Self {
name: name.to_string(),
required,
secret,
default: default.map(|s| s.to_string()),
oauth_flow: false,
primary,
}
}
pub fn from_value_type<T: ConfigValue>(required: bool, secret: bool) -> Self {
pub fn from_value_type<T: ConfigValue>(required: bool, secret: bool, primary: bool) -> Self {
Self {
name: T::KEY.to_string(),
required,
secret,
default: Some(T::DEFAULT.to_string()),
oauth_flow: false,
primary,
}
}
@@ -233,13 +245,20 @@ impl ConfigKey {
///
/// This is used for providers that support OAuth authentication instead of manual API key entry.
/// When oauth_flow is true, the configuration system will call the provider's configure_oauth() method.
pub fn new_oauth(name: &str, required: bool, secret: bool, default: Option<&str>) -> Self {
pub fn new_oauth(
name: &str,
required: bool,
secret: bool,
default: Option<&str>,
primary: bool,
) -> Self {
Self {
name: name.to_string(),
required,
secret,
default: default.map(|s| s.to_string()),
oauth_flow: true,
primary,
}
}
}
+3 -3
View File
@@ -277,9 +277,9 @@ impl ProviderDef for BedrockProvider {
BEDROCK_KNOWN_MODELS.to_vec(),
BEDROCK_DOC_LINK,
vec![
ConfigKey::new("AWS_PROFILE", false, false, Some("default")),
ConfigKey::new("AWS_REGION", false, false, None),
ConfigKey::new("AWS_BEARER_TOKEN_BEDROCK", false, true, None),
ConfigKey::new("AWS_PROFILE", false, false, Some("default"), true),
ConfigKey::new("AWS_REGION", false, false, None, true),
ConfigKey::new("AWS_BEARER_TOKEN_BEDROCK", false, true, None, true),
],
)
}
@@ -861,6 +861,7 @@ impl ProviderDef for ChatGptCodexProvider {
true,
true,
None,
false,
)],
)
.with_unlisted_models()
+3 -1
View File
@@ -483,7 +483,9 @@ impl ProviderDef for ClaudeCodeProvider {
// Only a few agentic choices; fetched dynamically via fetch_supported_models.
vec![],
CLAUDE_CODE_DOC_URL,
vec![ConfigKey::from_value_type::<ClaudeCodeCommand>(true, false)],
vec![ConfigKey::from_value_type::<ClaudeCodeCommand>(
true, false, true,
)],
)
// The model list only returns aliases the `claude` CLI uses, such as "default"
// and "haiku". There is no listing that includes full names like
+3 -3
View File
@@ -600,9 +600,9 @@ impl ProviderDef for CodexProvider {
CODEX_KNOWN_MODELS.to_vec(),
CODEX_DOC_URL,
vec![
ConfigKey::from_value_type::<CodexCommand>(true, false),
ConfigKey::from_value_type::<CodexReasoningEffort>(false, false),
ConfigKey::from_value_type::<CodexSkipGitCheck>(false, false),
ConfigKey::from_value_type::<CodexCommand>(true, false, true),
ConfigKey::from_value_type::<CodexReasoningEffort>(false, false, true),
ConfigKey::from_value_type::<CodexSkipGitCheck>(false, false, true),
],
)
.with_unlisted_models()
+1 -1
View File
@@ -291,7 +291,7 @@ impl ProviderDef for CursorAgentProvider {
CURSOR_AGENT_KNOWN_MODELS.to_vec(),
CURSOR_AGENT_DOC_URL,
vec![ConfigKey::from_value_type::<CursorAgentCommand>(
true, false,
true, false, true,
)],
)
.with_unlisted_models()
+2 -2
View File
@@ -246,8 +246,8 @@ impl ProviderDef for DatabricksProvider {
DATABRICKS_KNOWN_MODELS.to_vec(),
DATABRICKS_DOC_URL,
vec![
ConfigKey::new("DATABRICKS_HOST", true, false, None),
ConfigKey::new("DATABRICKS_TOKEN", false, true, None),
ConfigKey::new("DATABRICKS_HOST", true, false, None, true),
ConfigKey::new("DATABRICKS_TOKEN", false, true, None, true),
],
)
}
+6 -1
View File
@@ -503,36 +503,41 @@ impl ProviderDef for GcpVertexAIProvider {
KNOWN_MODELS.to_vec(),
GCP_VERTEX_AI_DOC_URL,
vec![
ConfigKey::new("GCP_PROJECT_ID", true, false, None),
ConfigKey::new("GCP_PROJECT_ID", true, false, None, true),
ConfigKey::new(
"GCP_LOCATION",
true,
false,
Some(&GcpLocation::Iowa.to_string()),
true,
),
ConfigKey::new(
"GCP_MAX_RETRIES",
false,
false,
Some(&DEFAULT_MAX_RETRIES.to_string()),
false,
),
ConfigKey::new(
"GCP_INITIAL_RETRY_INTERVAL_MS",
false,
false,
Some(&DEFAULT_INITIAL_RETRY_INTERVAL_MS.to_string()),
false,
),
ConfigKey::new(
"GCP_BACKOFF_MULTIPLIER",
false,
false,
Some(&DEFAULT_BACKOFF_MULTIPLIER.to_string()),
false,
),
ConfigKey::new(
"GCP_MAX_RETRY_INTERVAL_MS",
false,
false,
Some(&DEFAULT_MAX_RETRY_INTERVAL_MS.to_string()),
false,
),
],
)
+3 -1
View File
@@ -306,7 +306,9 @@ impl ProviderDef for GeminiCliProvider {
GEMINI_CLI_DEFAULT_MODEL,
GEMINI_CLI_KNOWN_MODELS.to_vec(),
GEMINI_CLI_DOC_URL,
vec![ConfigKey::from_value_type::<GeminiCliCommand>(true, false)],
vec![ConfigKey::from_value_type::<GeminiCliCommand>(
true, false, true,
)],
)
.with_unlisted_models()
}
@@ -395,6 +395,7 @@ impl ProviderDef for GithubCopilotProvider {
true,
true,
None,
false,
)],
)
}
+2 -2
View File
@@ -117,8 +117,8 @@ impl ProviderDef for GoogleProvider {
GOOGLE_KNOWN_MODELS.to_vec(),
GOOGLE_DOC_URL,
vec![
ConfigKey::new("GOOGLE_API_KEY", true, true, None),
ConfigKey::new("GOOGLE_HOST", false, false, Some(GOOGLE_API_HOST)),
ConfigKey::new("GOOGLE_API_KEY", true, true, None, true),
ConfigKey::new("GOOGLE_HOST", false, false, Some(GOOGLE_API_HOST), false),
],
)
}
+11 -4
View File
@@ -145,16 +145,23 @@ impl ProviderDef for LiteLLMProvider {
vec![],
LITELLM_DOC_URL,
vec![
ConfigKey::new("LITELLM_API_KEY", true, true, None),
ConfigKey::new("LITELLM_HOST", true, false, Some("http://localhost:4000")),
ConfigKey::new("LITELLM_API_KEY", true, true, None, true),
ConfigKey::new(
"LITELLM_HOST",
true,
false,
Some("http://localhost:4000"),
true,
),
ConfigKey::new(
"LITELLM_BASE_PATH",
true,
false,
Some("v1/chat/completions"),
false,
),
ConfigKey::new("LITELLM_CUSTOM_HEADERS", false, true, None),
ConfigKey::new("LITELLM_TIMEOUT", false, false, Some("600")),
ConfigKey::new("LITELLM_CUSTOM_HEADERS", false, true, None, false),
ConfigKey::new("LITELLM_TIMEOUT", false, false, Some("600"), false),
],
)
}
+2 -1
View File
@@ -158,12 +158,13 @@ impl ProviderDef for OllamaProvider {
OLLAMA_KNOWN_MODELS.to_vec(),
OLLAMA_DOC_URL,
vec![
ConfigKey::new("OLLAMA_HOST", true, false, Some(OLLAMA_HOST)),
ConfigKey::new("OLLAMA_HOST", true, false, Some(OLLAMA_HOST), true),
ConfigKey::new(
"OLLAMA_TIMEOUT",
false,
false,
Some(&(OLLAMA_TIMEOUT.to_string())),
false,
),
],
)
+19 -7
View File
@@ -285,13 +285,25 @@ impl ProviderDef for OpenAiProvider {
models,
OPEN_AI_DOC_URL,
vec![
ConfigKey::new("OPENAI_API_KEY", false, true, None),
ConfigKey::new("OPENAI_HOST", true, false, Some("https://api.openai.com")),
ConfigKey::new("OPENAI_BASE_PATH", true, false, Some("v1/chat/completions")),
ConfigKey::new("OPENAI_ORGANIZATION", false, false, None),
ConfigKey::new("OPENAI_PROJECT", false, false, None),
ConfigKey::new("OPENAI_CUSTOM_HEADERS", false, true, None),
ConfigKey::new("OPENAI_TIMEOUT", false, false, Some("600")),
ConfigKey::new("OPENAI_API_KEY", false, true, None, true),
ConfigKey::new(
"OPENAI_HOST",
true,
false,
Some("https://api.openai.com"),
false,
),
ConfigKey::new(
"OPENAI_BASE_PATH",
true,
false,
Some("v1/chat/completions"),
false,
),
ConfigKey::new("OPENAI_ORGANIZATION", false, false, None, false),
ConfigKey::new("OPENAI_PROJECT", false, false, None, false),
ConfigKey::new("OPENAI_CUSTOM_HEADERS", false, true, None, false),
ConfigKey::new("OPENAI_TIMEOUT", false, false, Some("600"), false),
],
)
}
+2 -1
View File
@@ -158,12 +158,13 @@ impl ProviderDef for OpenRouterProvider {
OPENROUTER_KNOWN_MODELS.to_vec(),
OPENROUTER_DOC_URL,
vec![
ConfigKey::new("OPENROUTER_API_KEY", true, true, None),
ConfigKey::new("OPENROUTER_API_KEY", true, true, None, true),
ConfigKey::new(
"OPENROUTER_HOST",
false,
false,
Some("https://openrouter.ai"),
false,
),
],
)
@@ -109,8 +109,13 @@ impl ProviderRegistry {
config_keys.remove(api_key_index);
} else if !config.api_key_env.is_empty() {
let api_key_required = provider_type == ProviderType::Declarative;
config_keys[api_key_index] =
super::base::ConfigKey::new(&config.api_key_env, api_key_required, true, None);
config_keys[api_key_index] = super::base::ConfigKey::new(
&config.api_key_env,
api_key_required,
true,
None,
true,
);
}
}
+3 -3
View File
@@ -284,9 +284,9 @@ impl ProviderDef for SageMakerTgiProvider {
vec![SAGEMAKER_TGI_DEFAULT_MODEL],
SAGEMAKER_TGI_DOC_LINK,
vec![
ConfigKey::new("SAGEMAKER_ENDPOINT_NAME", false, false, None),
ConfigKey::new("AWS_REGION", true, false, Some("us-east-1")),
ConfigKey::new("AWS_PROFILE", true, false, Some("default")),
ConfigKey::new("SAGEMAKER_ENDPOINT_NAME", true, false, None, true),
ConfigKey::new("AWS_REGION", true, false, Some("us-east-1"), true),
ConfigKey::new("AWS_PROFILE", true, false, Some("default"), true),
],
)
}
+2 -2
View File
@@ -309,8 +309,8 @@ impl ProviderDef for SnowflakeProvider {
SNOWFLAKE_KNOWN_MODELS.to_vec(),
SNOWFLAKE_DOC_URL,
vec![
ConfigKey::new("SNOWFLAKE_HOST", true, false, None),
ConfigKey::new("SNOWFLAKE_TOKEN", true, true, None),
ConfigKey::new("SNOWFLAKE_HOST", true, false, None, true),
ConfigKey::new("SNOWFLAKE_TOKEN", true, true, None, true),
],
)
}
+2 -1
View File
@@ -75,12 +75,13 @@ impl ProviderDef for TetrateProvider {
TETRATE_KNOWN_MODELS.to_vec(),
TETRATE_DOC_URL,
vec![
ConfigKey::new("TETRATE_API_KEY", true, true, None),
ConfigKey::new("TETRATE_API_KEY", true, true, None, true),
ConfigKey::new(
"TETRATE_HOST",
false,
false,
Some("https://api.router.tetrate.ai"),
false,
),
],
)
+4 -2
View File
@@ -205,19 +205,21 @@ impl ProviderDef for VeniceProvider {
FALLBACK_MODELS.to_vec(),
VENICE_DOC_URL,
vec![
ConfigKey::new("VENICE_API_KEY", true, true, None),
ConfigKey::new("VENICE_HOST", true, false, Some(VENICE_DEFAULT_HOST)),
ConfigKey::new("VENICE_API_KEY", true, true, None, true),
ConfigKey::new("VENICE_HOST", true, false, Some(VENICE_DEFAULT_HOST), false),
ConfigKey::new(
"VENICE_BASE_PATH",
true,
false,
Some(VENICE_DEFAULT_BASE_PATH),
false,
),
ConfigKey::new(
"VENICE_MODELS_PATH",
true,
false,
Some(VENICE_DEFAULT_MODELS_PATH),
false,
),
],
)
+2 -2
View File
@@ -45,8 +45,8 @@ impl ProviderDef for XaiProvider {
XAI_KNOWN_MODELS.to_vec(),
XAI_DOC_URL,
vec![
ConfigKey::new("XAI_API_KEY", true, true, None),
ConfigKey::new("XAI_HOST", false, false, Some(XAI_API_HOST)),
ConfigKey::new("XAI_API_KEY", true, true, None, true),
ConfigKey::new("XAI_HOST", false, false, Some(XAI_API_HOST), false),
],
)
}
+4
View File
@@ -3588,6 +3588,10 @@
"type": "boolean",
"description": "Whether this key should be configured using OAuth device code flow\nWhen true, the provider's configure_oauth() method will be called instead of prompting for manual input"
},
"primary": {
"type": "boolean",
"description": "Whether this key should be shown prominently during provider setup\n(onboarding, settings modal, CLI configure)"
},
"required": {
"type": "boolean",
"description": "Whether this key is required for the provider to function"
+5
View File
@@ -90,6 +90,11 @@ export type ConfigKey = {
* When true, the provider's configure_oauth() method will be called instead of prompting for manual input
*/
oauth_flow: boolean;
/**
* Whether this key should be shown prominently during provider setup
* (onboarding, settings modal, CLI configure)
*/
primary?: boolean;
/**
* Whether this key is required for the provider to function
*/
@@ -41,9 +41,10 @@ export default function ProviderConfigurationModal({
const [error, setError] = useState<string | null>(null);
const [isOAuthLoading, setIsOAuthLoading] = useState(false);
const requiredParameters = provider.metadata.config_keys.filter(
(param) => param.required === true
);
let primaryParameters = provider.metadata.config_keys.filter((param) => param.primary);
if (primaryParameters.length === 0) {
primaryParameters = provider.metadata.config_keys;
}
// Check if this provider uses OAuth for configuration
const isOAuthProvider = provider.metadata.config_keys.some((key) => key.oauth_flow);
@@ -238,7 +239,7 @@ export default function ProviderConfigurationModal({
validationErrors={validationErrors}
/>
{requiredParameters.length > 0 &&
{primaryParameters.length > 0 &&
provider.metadata.config_keys &&
provider.metadata.config_keys.length > 0 && <SecureStorageNotice />}
</>
@@ -260,7 +261,7 @@ export default function ProviderConfigurationModal({
</div>
) : (
<ProviderSetupActions
requiredParameters={requiredParameters}
primaryParameters={primaryParameters}
onCancel={handleCancel}
onSubmit={handleSubmitForm}
onDelete={handleDelete}
@@ -12,7 +12,7 @@ interface ProviderSetupActionsProps {
onCancelDelete?: () => void;
canDelete?: boolean;
providerName?: string;
requiredParameters?: ConfigKey[];
primaryParameters?: ConfigKey[];
isActiveProvider?: boolean; // Made optional with default false
}
@@ -29,7 +29,7 @@ export default function ProviderSetupActions({
onCancelDelete,
canDelete,
providerName,
requiredParameters,
primaryParameters,
isActiveProvider = false, // Default value provided
}: ProviderSetupActionsProps) {
// If we're showing delete confirmation, render the delete confirmation buttons
@@ -96,7 +96,7 @@ export default function ProviderSetupActions({
<Trash2 className="h-4 w-4 mr-2" /> Delete Provider
</Button>
)}
{requiredParameters && requiredParameters.length > 0 ? (
{primaryParameters && primaryParameters.length > 0 ? (
<>
<Button
type="submit"
@@ -168,10 +168,11 @@ export default function DefaultProviderSetupForm({
));
};
let aboveFoldParameters = parameters.filter((p) => p.required);
let belowFoldParameters = parameters.filter((p) => !p.required);
if (aboveFoldParameters.length === 0) {
aboveFoldParameters = belowFoldParameters;
let aboveFoldParameters = parameters.filter((p) => p.primary);
let belowFoldParameters = parameters.filter((p) => !p.primary);
if (aboveFoldParameters.length === 0 && parameters.length > 0) {
aboveFoldParameters = parameters;
belowFoldParameters = [];
}