| | <script lang="ts"> |
| | import { getContext } from 'svelte'; |
| | const i18n = getContext('i18n'); |
| | |
| | import Tooltip from '$lib/components/common/Tooltip.svelte'; |
| | import Plus from '$lib/components/icons/Plus.svelte'; |
| | import { WEBUI_BASE_URL } from '$lib/constants'; |
| | import Checkbox from '$lib/components/common/Checkbox.svelte'; |
| | import Badge from '$lib/components/common/Badge.svelte'; |
| | |
| | export let users = []; |
| | export let userIds = []; |
| | |
| | let filteredUsers = []; |
| | |
| | $: filteredUsers = users |
| | .filter((user) => { |
| | if (user?.role === 'admin') { |
| | return false; |
| | } |
| | |
| | if (query === '') { |
| | return true; |
| | } |
| | |
| | return ( |
| | user.name.toLowerCase().includes(query.toLowerCase()) || |
| | user.email.toLowerCase().includes(query.toLowerCase()) |
| | ); |
| | }) |
| | .sort((a, b) => { |
| | const aUserIndex = userIds.indexOf(a.id); |
| | const bUserIndex = userIds.indexOf(b.id); |
| | |
| | |
| | if (aUserIndex !== -1 && bUserIndex === -1) return -1; |
| | if (bUserIndex !== -1 && aUserIndex === -1) return 1; |
| | |
| | |
| | if (aUserIndex !== -1 && bUserIndex !== -1) return aUserIndex - bUserIndex; |
| | |
| | |
| | return a.name.localeCompare(b.name); |
| | }); |
| | |
| | let query = ''; |
| | </script> |
| |
|
| | <div> |
| | <div class="flex w-full"> |
| | <div class="flex flex-1"> |
| | <div class=" self-center mr-3"> |
| | <svg |
| | xmlns="http://www.w3.org/2000/svg" |
| | viewBox="0 0 20 20" |
| | fill="currentColor" |
| | class="w-4 h-4" |
| | > |
| | <path |
| | fill-rule="evenodd" |
| | d="M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z" |
| | clip-rule="evenodd" |
| | /> |
| | </svg> |
| | </div> |
| | <input |
| | class=" w-full text-sm pr-4 rounded-r-xl outline-hidden bg-transparent" |
| | bind:value={query} |
| | placeholder={$i18n.t('Search')} |
| | /> |
| | </div> |
| | </div> |
| |
|
| | <div class="mt-3 max-h-[22rem] overflow-y-auto scrollbar-hidden"> |
| | <div class="flex flex-col gap-2.5"> |
| | {#if filteredUsers.length > 0} |
| | {#each filteredUsers as user, userIdx (user.id)} |
| | <div class="flex flex-row items-center gap-3 w-full text-sm"> |
| | <div class="flex items-center"> |
| | <Checkbox |
| | state={userIds.includes(user.id) ? 'checked' : 'unchecked'} |
| | on:change={(e) => { |
| | if (e.detail === 'checked') { |
| | userIds = [...userIds, user.id]; |
| | } else { |
| | userIds = userIds.filter((id) => id !== user.id); |
| | } |
| | }} |
| | /> |
| | </div> |
| |
|
| | <div class="flex w-full items-center justify-between"> |
| | <Tooltip content={user.email} placement="top-start"> |
| | <div class="flex"> |
| | <img |
| | class=" rounded-full size-5 object-cover mr-2.5" |
| | src={user.profile_image_url.startsWith(WEBUI_BASE_URL) || |
| | user.profile_image_url.startsWith('https://www.gravatar.com/avatar/') || |
| | user.profile_image_url.startsWith('data:') |
| | ? user.profile_image_url |
| | : `/user.png`} |
| | alt="user" |
| | /> |
| |
|
| | <div class=" font-medium self-center">{user.name}</div> |
| | </div> |
| | </Tooltip> |
| |
|
| | {#if userIds.includes(user.id)} |
| | <Badge type="success" content="member" /> |
| | {/if} |
| | </div> |
| | </div> |
| | {/each} |
| | {:else} |
| | <div class="text-gray-500 text-xs text-center py-2 px-10"> |
| | {$i18n.t('No users were found.')} |
| | </div> |
| | {/if} |
| | </div> |
| | </div> |
| | </div> |
| |
|