Files
windmill/frontend/src/lib/components/InstanceNameEditor.svelte
T
GuilhemandClaude Opus 5 1901d3193b fix: keep the instance user editor popover inside the viewport (#10979)
* fix: keep the instance user editor popover inside the viewport

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A5v4NFqdTaZdkR8Ua1nr13

* fix: drop inert flex and min-h-0 classes from the user editor popover

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A5v4NFqdTaZdkR8Ua1nr13

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-05 10:38:44 +00:00

179 lines
4.6 KiB
Svelte

<script lang="ts">
import { stopPropagation, createBubbler } from 'svelte/legacy'
const bubble = createBubbler()
import { Pencil } from 'lucide-svelte'
import { createEventDispatcher } from 'svelte'
import Button from './common/button/Button.svelte'
import Popover from './meltComponents/Popover.svelte'
import ChangeInstanceUsernameInner from './ChangeInstanceUsernameInner.svelte'
import ChangeInstanceEmailInner from './ChangeInstanceEmailInner.svelte'
import { UserService } from '$lib/gen'
import { sendUserToast } from '$lib/toast'
import TextInput from './text_input/TextInput.svelte'
interface Props {
value: string | undefined
email: string
username?: string | undefined
automateUsernameCreation?: boolean
login_type: string
}
let {
value = $bindable(),
email,
username = undefined,
automateUsernameCreation = false,
login_type = $bindable()
}: Props = $props()
let password: string = $state('')
const dispatch = createEventDispatcher()
function saveName() {
dispatch('save', value)
}
async function savePassword() {
if (password.length < 5) {
sendUserToast('Password must be at least 5 characters long', true)
return
}
await UserService.setPasswordForUser({ user: email, requestBody: { password } })
sendUserToast(`Password updated for ${email}`)
}
async function saveLoginType() {
await UserService.setLoginTypeForUser({ user: email, requestBody: { login_type } })
sendUserToast(`Login type updated for ${email}`)
dispatch('refresh')
}
</script>
<Popover
floatingConfig={{ strategy: 'fixed', placement: 'left-end' }}
contentClasses="pt-9"
closeButton
>
{#snippet trigger()}
<Button unifiedSize="sm" nonCaptureEvent={true} variant="subtle" startIcon={{ icon: Pencil }}
>Edit</Button
>
{/snippet}
{#snippet content()}
<!-- The scroll sits here rather than on the popover box, which is what the close button
is positioned against — box-level overflow scrolls that button out of reach. The
box's `pt-9` clears the button's 34px, so the scrollbar starts below it. -->
<div class="flex flex-col gap-8 max-w-sm p-4 pt-0 max-h-[70vh] overflow-y-auto">
<ChangeInstanceEmailInner
{email}
{username}
noPadding
on:changed={() => dispatch('refresh')}
/>
{#if automateUsernameCreation && username}
<ChangeInstanceUsernameInner {email} {username} on:renamed noPadding />
{/if}
<label class="block text-primary">
<div class="pb-1 text-xs font-semibold text-emphasis">Name</div>
<div class="flex w-full">
<TextInput
inputProps={{
onclick: (e) => {
e.stopPropagation()
},
onkeydown: (e) => {
e.stopPropagation()
},
onkeypress: ({ key }) => {
if (key === 'Enter') {
saveName()
}
}
}}
bind:value
/>
</div>
<Button
unifiedSize="md"
variant="default"
buttonType="button"
btnClasses="mt-2 "
aria-label="Save ID"
onclick={() => {
saveName()
}}
>
Update name
</Button>
</label>
<label class="block text-primary">
<div class="pb-1 text-xs font-semibold text-emphasis">Password</div>
<div class="flex w-full">
<input
type="password"
bind:value={password}
class="!w-auto grow"
onclick={stopPropagation(() => {})}
onkeydown={stopPropagation(bubble('keydown'))}
onkeypress={(e) => {
e.stopPropagation()
if (e.key === 'Enter') {
savePassword()
}
}}
/>
</div>
<Button
unifiedSize="md"
variant="default"
buttonType="button"
btnClasses="mt-2 "
aria-label="Save ID"
on:click={() => {
savePassword()
}}
>
Update password
</Button>
</label>
<label class="block text-primary">
<div class="mb-1 text-xs font-semibold text-emphasis">Login type</div>
<div class="flex w-full">
<input
type="text"
bind:value={login_type}
class="!w-auto grow"
onclick={stopPropagation(() => {})}
onkeydown={stopPropagation(bubble('keydown'))}
onkeypress={(e) => {
e.stopPropagation()
if (e.key === 'Enter') {
saveLoginType()
}
}}
/>
</div>
<div class="text-2xs text-secondary mb-1">
Must match exact SSO name, "password" or "saml". Examples: password, google, saml,
microsoft
</div>
<Button
unifiedSize="md"
variant="default"
buttonType="button"
btnClasses="mt-2 "
aria-label="Save login type"
on:click={() => {
saveLoginType()
}}
>
Update login type
</Button>
</label>
</div>
{/snippet}
</Popover>