Skip to content
Merged
8 changes: 5 additions & 3 deletions app/web_ui/src/lib/ui/dialog.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
disabled?: boolean
loading?: boolean
hide?: boolean
width?: "normal" | "wide"
}
export let action_buttons: ActionButton[] = []
let action_running = false
Expand Down Expand Up @@ -187,9 +188,9 @@
</form>
{:else}
<button
class="btn btn-sm h-10 min-w-24 {button.isPrimary
? 'btn-primary'
: ''}
class="btn btn-sm h-10 min-w-24 {button.width === 'wide'
? 'w-full'
: ''} {button.isPrimary ? 'btn-primary' : ''}
{button.isError ? 'btn-error' : ''}
{button.isWarning ? 'btn-warning' : ''}"
disabled={button.disabled || button.loading}
Expand All @@ -205,6 +206,7 @@
{/if}
</div>
{/if}
<slot name="footer" />
</div>
</div>
<form
Expand Down
210 changes: 210 additions & 0 deletions app/web_ui/src/lib/ui/kiln_copilot/connect_kiln_copilot_steps.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
<script lang="ts">
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is all extracted out from app/web_ui/src/routes/(fullscreen)/setup/(setup)/connect_providers/kiln_copilot/connect_kiln_copilot.svelte

import { onMount } from "svelte"
import createKindeClient from "@kinde-oss/kinde-auth-pkce-js"
import { base_url } from "$lib/api_client"
import posthog from "posthog-js"
import { env } from "$env/dynamic/public"

export let onSuccess: () => void
export let showTitle = true
export let small = false
export let showCheckmark = false

let kindeClient: Awaited<ReturnType<typeof createKindeClient>> | null = null
let apiKey = ""
let apiKeyError = false
let apiKeyMessage: string | null = null
let submitting = false

const KINDE_ACCOUNT_DOMAIN =
env.PUBLIC_KINDE_ACCOUNT_DOMAIN || "https://account.kiln.tech"
const KINDE_ACCOUNT_CLIENT_ID =
env.PUBLIC_KINDE_ACCOUNT_CLIENT_ID || "2428f47a1e0b404b82e68400a2d580c6"

async function initKindeClient() {
if (kindeClient) return kindeClient

kindeClient = await createKindeClient({
client_id: KINDE_ACCOUNT_CLIENT_ID,
domain: KINDE_ACCOUNT_DOMAIN,
redirect_uri: window.location.origin + window.location.pathname,
on_redirect_callback: () => {},
})

return kindeClient
}

async function openSignup() {
try {
const kinde = await initKindeClient()
if (!kinde) {
apiKeyError = true
apiKeyMessage = "Kinde configuration is missing"
return
}

await kinde.register()
} catch (e) {
console.error("openSignup error", e)
apiKeyError = true
apiKeyMessage = "Failed to open Kiln Copilot signup"
}
}

async function openSelfServePortal() {
try {
const kinde = await initKindeClient()
if (!kinde) {
apiKeyError = true
apiKeyMessage = "Please sign up first"
return
}

const accessToken = await kinde.getToken()
if (!accessToken) {
apiKeyError = true
apiKeyMessage = "Please sign up first before accessing the portal"
return
}

const response = await fetch(
`${KINDE_ACCOUNT_DOMAIN}/account_api/v1/portal_link`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
sub_nav: "api_keys",
},
},
)

if (!response.ok) {
throw new Error("Failed to generate portal link")
}

const data = await response.json()
window.open(data.url, "_blank")
} catch (e) {
console.error("openSelfServePortal error", e)
apiKeyError = true
apiKeyMessage =
"Failed to open self-serve portal. Please try signing up first."
}
}

export async function submitApiKey() {
if (!apiKey.trim()) {
apiKeyError = true
return false
}

apiKeyError = false
apiKeyMessage = null
submitting = true

try {
const res = await fetch(base_url + "/api/provider/connect_api_key", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
provider: "kiln_copilot",
key_data: {
"API Key": apiKey,
},
}),
})

const data = await res.json()

if (!res.ok) {
apiKeyMessage =
data.message || data.detail || "Failed to connect to provider"
apiKeyError = true
return false
}

posthog.capture("connect_provider", {
provider_id: "kiln_copilot",
})

onSuccess()
return true
} catch (e) {
console.error("submitApiKey error", e)
apiKeyMessage = "Failed to connect to provider (Exception: " + e + ")"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like we could now use your server error message now and throw from inside the try and turn it into a KilnError like we usually do for failing API calls. Probably not in scope of this PR though

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

created KIL-354 for that!

apiKeyError = true
return false
} finally {
submitting = false
}
}

onMount(async () => {
if (
window.location.search.includes("code=") ||
window.location.search.includes("state=")
) {
await initKindeClient()
}
})
</script>

{#if showTitle}
<h1 class="text-{small ? 'lg' : 'xl'} font-medium text-center mb-2">
Connect Kiln Copilot
</h1>
{/if}

<ol class="my-2 text-gray-700 {small ? 'text-sm' : ''}">
<li class="list-decimal pl-1 mx-8 my-4">
<button class="link" on:click={openSignup}>Sign Up</button>
to create your Kiln Copilot account.
</li>
<li class="list-decimal pl-1 mx-8 my-4">
After registration,
<button class="link" on:click={openSelfServePortal}>
open the self-serve portal.
</button>
Go to 'API keys' section and create an API key.
</li>
<li class="list-decimal pl-1 mx-8 my-4">
Copy your API key, paste it below and click 'Connect'.
</li>
</ol>

{#if apiKeyMessage}
<p class="text-error text-center pb-4">{apiKeyMessage}</p>
{/if}

<div class="flex flex-row gap-4 items-center">
<div class="grow flex flex-col gap-2">
<input
type="text"
id="API Key"
placeholder="API Key"
class="input input-bordered w-full max-w-[300px] {apiKeyError
? 'input-error'
: ''}"
bind:value={apiKey}
on:input={() => (apiKeyError = false)}
/>
</div>
<button
class="btn min-w-[130px]"
on:click={submitApiKey}
disabled={submitting}
>
{#if submitting}
<div class="loading loading-spinner loading-md"></div>
{:else if showCheckmark}
<img
src="/images/circle-check.svg"
class="size-6 group-hover:hidden"
alt="Connected"
/>
{:else}
Connect
{/if}
</button>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</script>

<AppPage
title="Connect Kiln Copilot"
title="Kiln Copilot"
breadcrumbs={[
{ label: "Settings", href: "/settings" },
{ label: "AI Providers", href: "/settings/providers" },
Expand Down
Loading
Loading