File size: 3,725 Bytes
bc27e65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
<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);



			// Compare based on userIds or fall back to alphabetical order

			if (aUserIndex !== -1 && bUserIndex === -1) return -1; // 'a' has valid userId -> prioritize

			if (bUserIndex !== -1 && aUserIndex === -1) return 1; // 'b' has valid userId -> prioritize



			// Both a and b are either in the userIds array or not, so we'll sort them by their indices

			if (aUserIndex !== -1 && bUserIndex !== -1) return aUserIndex - bUserIndex;



			// If both are not in the userIds, fallback to alphabetical sorting by name

			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>