reolace addUser popup with popover

This commit is contained in:
Guilhem
2025-02-12 11:01:16 +00:00
parent 7df118e7d6
commit dc32bcb2d6
5 changed files with 89 additions and 80 deletions

View File

@@ -2,7 +2,8 @@
import { createEventDispatcher } from 'svelte'
import { globalEmailInvite, superadmin, workspaceStore } from '$lib/stores'
import { SettingService, UserService, WorkspaceService } from '$lib/gen'
import { Button, Popup } from './common'
import { Button } from './common'
import Popover from './meltComponents/Popover.svelte'
import { sendUserToast } from '$lib/toast'
import { isCloudHosted } from '$lib/cloud'
import { goto } from '$lib/navigation'
@@ -72,64 +73,63 @@
let selected: 'operator' | 'developer' | 'admin' = 'developer'
</script>
<Popup
floatingConfig={{ strategy: 'absolute', placement: 'bottom-end' }}
containerClasses="border rounded-lg shadow-lg p-4 bg-surface"
>
<svelte:fragment slot="button">
<Popover placement="bottom-end">
<svelte:fragment slot="trigger">
<Button color="dark" size="xs" nonCaptureEvent={true} startIcon={{ icon: UserPlus }}>
Add new user
</Button>
</svelte:fragment>
<div class="flex flex-col w-72 p-2">
<span class="text-sm mb-2 leading-6 font-semibold">Add a new user</span>
<svelte:fragment slot="content">
<div class="flex flex-col w-72 p-4">
<span class="text-sm mb-2 leading-6 font-semibold">Add a new user</span>
<span class="text-xs mb-1 leading-6">Email</span>
<input type="email mb-1" on:keyup={handleKeyUp} placeholder="email" bind:value={email} />
<span class="text-xs mb-1 leading-6">Email</span>
<input type="email mb-1" on:keyup={handleKeyUp} placeholder="email" bind:value={email} />
{#if !automateUsernameCreation}
<span class="text-xs mb-1 pt-2 leading-6">Username</span>
<input type="text" on:keyup={handleKeyUp} placeholder="username" bind:value={username} />
{/if}
{#if !automateUsernameCreation}
<span class="text-xs mb-1 pt-2 leading-6">Username</span>
<input type="text" on:keyup={handleKeyUp} placeholder="username" bind:value={username} />
{/if}
<span class="text-xs mb-1 pt-2 leading-6">Role</span>
<ToggleButtonGroup bind:selected class="mb-4">
<ToggleButton
value="operator"
<span class="text-xs mb-1 pt-2 leading-6">Role</span>
<ToggleButtonGroup bind:selected class="mb-4">
<ToggleButton
value="operator"
size="sm"
label="Operator"
tooltip="An operator can only execute and view scripts/flows/apps from your workspace, and only those that he has visibility on."
/>
<ToggleButton
position="center"
value="developer"
size="sm"
label="Developer"
tooltip="A Developer can execute and view scripts/flows/apps, but they can also create new ones and edit those they are allowed to by their path (either u/ or Writer or Admin of their folder found at /f)."
/>
<ToggleButton
position="right"
value="admin"
size="sm"
label="Admin"
tooltip="An admin has full control over a specific Windmill workspace, including the ability to manage users, edit entities, and control permissions within the workspace."
/>
</ToggleButtonGroup>
<Button
variant="contained"
color="blue"
size="sm"
label="Operator"
tooltip="An operator can only execute and view scripts/flows/apps from your workspace, and only those that he has visibility on."
/>
<ToggleButton
position="center"
value="developer"
size="sm"
label="Developer"
tooltip="A Developer can execute and view scripts/flows/apps, but they can also create new ones and edit those they are allowed to by their path (either u/ or Writer or Admin of their folder found at /f)."
/>
<ToggleButton
position="right"
value="admin"
size="sm"
label="Admin"
tooltip="An admin has full control over a specific Windmill workspace, including the ability to manage users, edit entities, and control permissions within the workspace."
/>
</ToggleButtonGroup>
<Button
variant="contained"
color="blue"
size="sm"
on:click={() => {
addUser().then(() => {
// @ts-ignore
email = undefined
// @ts-ignore
username = undefined
})
}}
disabled={email === undefined || (!automateUsernameCreation && username === undefined)}
>
Add
</Button>
</div>
</Popup>
on:click={() => {
addUser().then(() => {
// @ts-ignore
email = undefined
// @ts-ignore
username = undefined
})
}}
disabled={email === undefined || (!automateUsernameCreation && username === undefined)}
>
Add
</Button>
</div>
</svelte:fragment>
</Popover>

View File

@@ -2,16 +2,17 @@
import { createPopover, createSync, melt } from '@melt-ui/svelte'
import { fade } from 'svelte/transition'
import { X } from 'lucide-svelte'
import type { Placement } from '@floating-ui/core'
import { zIndexes } from '$lib/zIndexes'
export let open = false
export let closeButton: boolean = true
export let closeButton: boolean = false
export let displayArrow: boolean = false
export let placement: any = 'bottom'
export let placement: Placement = 'bottom'
export let disablePopup: boolean = false
export let openOnHover: boolean = false
const {
elements: { trigger, content, arrow, close },
elements: { trigger, content, arrow, close: closeElement },
states
} = createPopover({
forceVisible: true,
@@ -20,29 +21,42 @@
}
})
let isOpen = false
const sync = createSync(states)
$: sync.open(open, (v) => (open = v))
$: sync.open(isOpen, (v) => (isOpen = v))
export function close() {
isOpen = false
}
export function open() {
isOpen = true
}
</script>
<button
class="w-full h-full"
type="button"
<div
class={$$props.class}
use:melt={$trigger}
aria-label="Popup button"
on:mouseenter={() => (openOnHover ? (open = true) : null)}
on:mouseleave={() => (openOnHover ? (open = false) : null)}
on:mouseenter={() => (openOnHover ? open() : null)}
on:mouseleave={() => (openOnHover ? close() : null)}
>
<slot name="trigger" />
</button>
</div>
{#if open}
<div use:melt={$content} transition:fade={{ duration: 100 }} class="content z-[9999]">
{#if isOpen && !disablePopup}
<div
use:melt={$content}
transition:fade={{ duration: 100 }}
class="w-fit rounded-md bg-surface overflow-hidden shadow-md"
style="z-index: {zIndexes.popover}"
>
{#if displayArrow}
<div use:melt={$arrow} />
{/if}
<slot name="content" />
<slot name="content" {open} {close} />
{#if closeButton}
<button class="close" use:melt={$close}>
<button class="close" use:melt={$closeElement}>
<X class="size-3" />
</button>
{/if}
@@ -56,8 +70,4 @@
@apply focus-visible:ring focus-visible:ring-gray-400 focus-visible:ring-offset-2;
@apply bg-surface p-0 text-sm font-medium;
}
.content {
@apply w-fit rounded-[4px] bg-surface p-0 overflow-hidden shadow-md;
}
</style>

View File

@@ -13,15 +13,13 @@
dispatch('add', { name })
name = ''
}
let open: boolean = false
</script>
<Popover closeButton={false} bind:open>
<Popover closeButton={false}>
<svelte:fragment slot="trigger">
<slot name="trigger" />
</svelte:fragment>
<svelte:fragment slot="content">
<svelte:fragment slot="content" let:close>
<div class="flex flex-row gap-2 p-2 rounded-md">
<input
bind:value={name}
@@ -29,7 +27,7 @@
on:keydown={(event) => {
if (event.key === 'Enter') {
addField()
open = false
close()
}
}}
/>
@@ -40,7 +38,7 @@
id="flow-editor-add-property"
on:click={() => {
addField()
open = false
close()
}}
disabled={!name}
shortCut={{ Icon: CornerDownLeft, withoutModifier: true }}

View File

@@ -25,7 +25,7 @@
}
</script>
<Popover closeButton={false} bind:open={isOpen}>
<Popover closeButton={false} bind:isOpen>
<svelte:fragment slot="trigger">
{#if small}
<Button

View File

@@ -5,6 +5,7 @@ export const zIndexes = {
colorInput: 1002,
disposables: 1100, // Modals and Drawers
svelteSelectOptions: 5000,
popover: 5001,
contextMenu: 6000,
draggingComponent: 10000,
monacoEditor: 10000,