mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 01:18:34 +00:00
set api keys works
This commit is contained in:
1 parent
d01012b539
commit
9c9e1fe099
2 files changed
+62
-17
No files matched your search
@@ -39,6 +39,8 @@ pub struct ProviderListEntry {
|
||||
pub struct ProviderCredentialDetails {
|
||||
/// For API keys: the first few characters followed by asterisks.
|
||||
pub maybe_key_start: Option<String>,
|
||||
/// For API keys: the full key value.
|
||||
pub maybe_full_key: Option<String>,
|
||||
/// For web logins: the email address if available.
|
||||
pub maybe_email_address: Option<String>,
|
||||
/// For web logins: the username if available.
|
||||
@@ -68,6 +70,7 @@ pub async fn provider_list_command(
|
||||
ProviderCredentialPayload::ApiKey(data) => {
|
||||
ProviderCredentialDetails {
|
||||
maybe_key_start: Some(redact_key(data.as_str())),
|
||||
maybe_full_key: Some(data.as_str().to_string()),
|
||||
maybe_email_address: None,
|
||||
maybe_username: None,
|
||||
}
|
||||
@@ -75,6 +78,7 @@ pub async fn provider_list_command(
|
||||
ProviderCredentialPayload::WebLogin(data) => {
|
||||
ProviderCredentialDetails {
|
||||
maybe_key_start: None,
|
||||
maybe_full_key: None,
|
||||
maybe_email_address: data.email_address,
|
||||
maybe_username: data.username,
|
||||
}
|
||||
|
||||
+58
-17
@@ -13,6 +13,7 @@ type ProviderCredentialKey =
|
||||
|
||||
interface ProviderCredentialDetails {
|
||||
maybe_key_start: string | null;
|
||||
maybe_full_key: string | null;
|
||||
maybe_email_address: string | null;
|
||||
maybe_username: string | null;
|
||||
}
|
||||
@@ -34,36 +35,62 @@ interface ApiKeyRowProps {
|
||||
label: string;
|
||||
credentialKey: ProviderCredentialKey;
|
||||
initialRedactedValue: string;
|
||||
hasCredentials: boolean;
|
||||
initialFullKey: string;
|
||||
}
|
||||
|
||||
const ApiKeyRow = ({
|
||||
label,
|
||||
credentialKey,
|
||||
initialRedactedValue,
|
||||
hasCredentials,
|
||||
initialFullKey,
|
||||
}: ApiKeyRowProps) => {
|
||||
const [value, setValue] = useState("");
|
||||
// The actual key value (editable).
|
||||
const [fullKey, setFullKey] = useState(initialFullKey);
|
||||
// The redacted display value.
|
||||
const [redacted, setRedacted] = useState(initialRedactedValue);
|
||||
// Whether the input is focused (show real value vs redacted).
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
// Track if user changed something since last save.
|
||||
const [isDirty, setIsDirty] = useState(false);
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const newValue = e.target.value;
|
||||
console.log(`[ProviderCredentials] onChange fired for ${credentialKey}: "${newValue}"`);
|
||||
setValue(newValue);
|
||||
setFullKey(newValue);
|
||||
setIsDirty(true);
|
||||
};
|
||||
|
||||
if (newValue.trim() === "") {
|
||||
console.log(`[ProviderCredentials] Clearing ${credentialKey}...`);
|
||||
const handleFocus = () => {
|
||||
setIsFocused(true);
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
setIsFocused(false);
|
||||
|
||||
if (!isDirty) return;
|
||||
setIsDirty(false);
|
||||
|
||||
const trimmed = fullKey.trim();
|
||||
|
||||
if (trimmed === "") {
|
||||
invoke("provider_clear_command", {
|
||||
request: { provider_credential: credentialKey },
|
||||
}).then(() => {
|
||||
setFullKey("");
|
||||
setRedacted("");
|
||||
console.log(`[ProviderCredentials] Cleared ${credentialKey}`);
|
||||
}).catch((e) => {
|
||||
console.error(`[ProviderCredentials] Error clearing ${credentialKey}:`, e);
|
||||
});
|
||||
} else {
|
||||
console.log(`[ProviderCredentials] Saving ${credentialKey}...`);
|
||||
invoke("provider_set_api_key_command", {
|
||||
request: { provider_credential: credentialKey, api_key: newValue },
|
||||
request: { provider_credential: credentialKey, api_key: trimmed },
|
||||
}).then(() => {
|
||||
setFullKey(trimmed);
|
||||
setRedacted(
|
||||
trimmed.length > 6
|
||||
? trimmed.substring(0, 6) + "********"
|
||||
: "********"
|
||||
);
|
||||
console.log(`[ProviderCredentials] Saved ${credentialKey}`);
|
||||
}).catch((e) => {
|
||||
console.error(`[ProviderCredentials] Error saving ${credentialKey}:`, e);
|
||||
@@ -71,15 +98,27 @@ const ApiKeyRow = ({
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === "Enter") {
|
||||
(e.target as HTMLInputElement).blur();
|
||||
}
|
||||
};
|
||||
|
||||
const hasKey = isFocused ? fullKey.length > 0 : redacted.length > 0;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<label className="mb-1 block text-sm">{label}</label>
|
||||
<input
|
||||
type="password"
|
||||
value={value}
|
||||
type={isFocused ? "text" : "password"}
|
||||
value={isFocused ? fullKey : (redacted || "")}
|
||||
onChange={handleChange}
|
||||
placeholder={hasCredentials ? initialRedactedValue : "Enter API Key"}
|
||||
className="h-10 w-full rounded-lg px-3 py-2.5 outline-none bg-ui-panel text-base-fg placeholder-base-fg/50 border border-ui-panel-border"
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder="Enter API Key"
|
||||
className="h-10 w-full rounded-lg px-3 py-2.5 outline-none bg-ui-panel text-base-fg placeholder-base-fg/50 border border-ui-panel-border transition-all duration-150 ease-in-out hover:border-primary/60 focus:border-primary"
|
||||
readOnly={!isFocused}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -94,11 +133,9 @@ export const ProviderCredentialsGroupBlock = () => {
|
||||
useEffect(() => {
|
||||
const fetchProviders = async () => {
|
||||
try {
|
||||
console.log("[ProviderCredentials] Fetching provider list...");
|
||||
const result = (await invoke("provider_list_command")) as {
|
||||
payload: ProviderListResponse;
|
||||
};
|
||||
console.log("[ProviderCredentials] Got providers:", result.payload.providers);
|
||||
setProviders(result.payload.providers);
|
||||
} catch (e) {
|
||||
console.error("[ProviderCredentials] Error fetching provider list:", e);
|
||||
@@ -128,7 +165,9 @@ export const ProviderCredentialsGroupBlock = () => {
|
||||
initialRedactedValue={
|
||||
falProvider?.maybe_details?.maybe_key_start ?? ""
|
||||
}
|
||||
hasCredentials={falProvider?.has_credentials ?? false}
|
||||
initialFullKey={
|
||||
falProvider?.maybe_details?.maybe_full_key ?? ""
|
||||
}
|
||||
/>
|
||||
<ApiKeyRow
|
||||
label="Replicate API Key (optional)"
|
||||
@@ -136,7 +175,9 @@ export const ProviderCredentialsGroupBlock = () => {
|
||||
initialRedactedValue={
|
||||
replicateProvider?.maybe_details?.maybe_key_start ?? ""
|
||||
}
|
||||
hasCredentials={replicateProvider?.has_credentials ?? false}
|
||||
initialFullKey={
|
||||
replicateProvider?.maybe_details?.maybe_full_key ?? ""
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user