|
3 | 3 | import { CopyInput, Modal } from '$lib/components'; |
4 | 4 | import { |
5 | 5 | Button, |
| 6 | + InputNumber, |
6 | 7 | InputPassword, |
7 | 8 | InputSwitch, |
8 | 9 | InputText, |
9 | 10 | InputTextarea |
10 | 11 | } from '$lib/elements/forms'; |
11 | 12 | import { updateOAuth } from '../updateOAuth'; |
12 | | - import { OAuthProvider, type Models as ConsoleModels } from '@appwrite.io/console'; |
| 13 | + import { |
| 14 | + OAuthProvider, |
| 15 | + ProjectOAuth2OidcPrompt, |
| 16 | + type Models as ConsoleModels |
| 17 | + } from '@appwrite.io/console'; |
13 | 18 | import type { AuthProvider } from '../updateOAuth'; |
14 | 19 | import { oAuthProviders } from '$lib/stores/oauth-providers'; |
15 | 20 | import { |
|
25 | 30 | } from '@appwrite.io/pink-svelte'; |
26 | 31 | import { IconDocument, IconPencil, IconUpload, IconX } from '@appwrite.io/pink-icons-svelte'; |
27 | 32 | import { getApiEndpoint } from '$lib/stores/sdk'; |
| 33 | + import OidcPromptPicker from './oidcPromptPicker.svelte'; |
28 | 34 |
|
29 | 35 | const projectId = page.params.project; |
30 | 36 | const region = page.params.region; |
|
44 | 50 | let initialEnabled = false; |
45 | 51 | let initialAppId: string | null = null; |
46 | 52 | let initialDetailValues: Record<string, string> = {}; |
| 53 | + let oidcPrompt: ProjectOAuth2OidcPrompt[] = []; |
| 54 | + let initialOidcPrompt: ProjectOAuth2OidcPrompt[] = []; |
| 55 | + let oidcMaxAge: number | null = null; |
| 56 | + let initialOidcMaxAge: number | null = null; |
47 | 57 |
|
| 58 | + $: isOidc = provider?.key === OAuthProvider.Oidc; |
48 | 59 | $: appIdParam = parameters.length >= 1 ? parameters[0] : null; |
49 | 60 | $: additionalParams = parameters.slice(1); |
50 | 61 | $: detailParams = additionalParams.filter((param) => !isSecretParam(param.$id)); |
51 | 62 | $: secretParams = additionalParams.filter((param) => isSecretParam(param.$id)); |
52 | 63 | $: basicDetailParams = |
53 | 64 | provider?.key === OAuthProvider.Oidc |
54 | | - ? detailParams.filter((param) => !isOidcAdvancedParam(param.$id)) |
| 65 | + ? detailParams.filter( |
| 66 | + (param) => !isOidcAdvancedParam(param.$id) && !isOidcCustomParam(param.$id) |
| 67 | + ) |
55 | 68 | : detailParams; |
56 | 69 | $: advancedDetailParams = |
57 | 70 | provider?.key === OAuthProvider.Oidc |
|
66 | 79 | normalizeFieldValue(fieldValues[param.$id]) !== (initialDetailValues[param.$id] ?? '') |
67 | 80 | ); |
68 | 81 | }); |
| 82 | + $: hasOidcChanges = |
| 83 | + isOidc && |
| 84 | + ([...oidcPrompt].sort().join(',') !== [...initialOidcPrompt].sort().join(',') || |
| 85 | + (oidcMaxAge ?? 0) !== (initialOidcMaxAge ?? 0)); |
69 | 86 | $: nothingChanged = |
70 | 87 | enabled === initialEnabled && |
71 | 88 | normalizeFieldValue(appId) === normalizeFieldValue(initialAppId) && |
72 | 89 | !hasSecretInput && |
73 | | - !hasDetailChanges; |
| 90 | + !hasDetailChanges && |
| 91 | + !hasOidcChanges; |
74 | 92 | $: oAuthProvider = oAuthProviders[provider.key]; |
75 | 93 | $: secretCardTitle = |
76 | 94 | secretParams.length === 1 ? primaryName(secretParams[0]?.name ?? '') : 'Credentials'; |
|
90 | 108 | ); |
91 | 109 | p8PasteMode = {}; |
92 | 110 | showSecretInput = !appId || (provider.key === OAuthProvider.Apple && !providerKeyId); |
| 111 | + if (provider.key === OAuthProvider.Oidc) { |
| 112 | + const raw = provider as Record<string, unknown>; |
| 113 | + initialOidcPrompt = Array.isArray(raw['prompt']) |
| 114 | + ? ([...(raw['prompt'] as ProjectOAuth2OidcPrompt[])] as ProjectOAuth2OidcPrompt[]) |
| 115 | + : []; |
| 116 | + initialOidcMaxAge = |
| 117 | + typeof raw['maxAge'] === 'number' && raw['maxAge'] > 0 ? raw['maxAge'] : null; |
| 118 | + } else { |
| 119 | + initialOidcPrompt = []; |
| 120 | + initialOidcMaxAge = null; |
| 121 | + } |
| 122 | + oidcPrompt = [...initialOidcPrompt]; |
| 123 | + oidcMaxAge = initialOidcMaxAge; |
93 | 124 | error = undefined; |
94 | 125 | } |
95 | 126 |
|
|
151 | 182 | return id !== 'wellKnownURL' && id.toLowerCase().includes('url'); |
152 | 183 | } |
153 | 184 |
|
| 185 | + // prompt and maxAge get dedicated controls in the Advanced section |
| 186 | + function isOidcCustomParam(id: string): boolean { |
| 187 | + return id === 'prompt' || id === 'maxAge'; |
| 188 | + } |
| 189 | +
|
154 | 190 | async function handleP8FileUpload(id: string, event: Event) { |
155 | 191 | const input = event.target as HTMLInputElement; |
156 | 192 | const file = input.files?.[0]; |
|
198 | 234 | appId, |
199 | 235 | secret: buildSecret(), |
200 | 236 | details: buildDetails(), |
| 237 | + promptValues: isOidc ? oidcPrompt : undefined, |
| 238 | + maxAge: isOidc ? (oidcMaxAge ?? 0) : undefined, |
201 | 239 | enabled |
202 | 240 | }); |
203 | 241 |
|
|
357 | 395 | {/if} |
358 | 396 | {/if} |
359 | 397 |
|
360 | | - {#if advancedDetailParams.length > 0} |
| 398 | + {#if advancedDetailParams.length > 0 || isOidc} |
361 | 399 | <Accordion title="Advanced" badge="Optional" hideDivider> |
362 | 400 | <Layout.Stack gap="l"> |
363 | 401 | {#each advancedDetailParams as param} |
|
368 | 406 | helper={helperText(param.hint)} |
369 | 407 | bind:value={fieldValues[param.$id]} /> |
370 | 408 | {/each} |
| 409 | + {#if isOidc} |
| 410 | + <OidcPromptPicker bind:value={oidcPrompt} /> |
| 411 | + <InputNumber |
| 412 | + id="maxAge" |
| 413 | + label="Max age" |
| 414 | + placeholder="3600" |
| 415 | + min={0} |
| 416 | + nullable |
| 417 | + helper="Maximum authentication age in seconds. If exceeded, the user must re-authenticate. Leave empty to disable." |
| 418 | + bind:value={oidcMaxAge} /> |
| 419 | + {/if} |
371 | 420 | </Layout.Stack> |
372 | 421 | </Accordion> |
373 | 422 | {/if} |
|
0 commit comments