Users.svelte 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. <script lang="ts">
  2. import { getContext } from 'svelte';
  3. const i18n = getContext('i18n');
  4. import Tooltip from '$lib/components/common/Tooltip.svelte';
  5. import Plus from '$lib/components/icons/Plus.svelte';
  6. import { WEBUI_BASE_URL } from '$lib/constants';
  7. import Checkbox from '$lib/components/common/Checkbox.svelte';
  8. import Badge from '$lib/components/common/Badge.svelte';
  9. import Search from '$lib/components/icons/Search.svelte';
  10. export let users = [];
  11. export let userIds = [];
  12. let filteredUsers = [];
  13. $: filteredUsers = users
  14. .filter((user) => {
  15. if (query === '') {
  16. return true;
  17. }
  18. return (
  19. user.name.toLowerCase().includes(query.toLowerCase()) ||
  20. user.email.toLowerCase().includes(query.toLowerCase())
  21. );
  22. })
  23. .sort((a, b) => {
  24. const aUserIndex = userIds.indexOf(a.id);
  25. const bUserIndex = userIds.indexOf(b.id);
  26. // Compare based on userIds or fall back to alphabetical order
  27. if (aUserIndex !== -1 && bUserIndex === -1) return -1; // 'a' has valid userId -> prioritize
  28. if (bUserIndex !== -1 && aUserIndex === -1) return 1; // 'b' has valid userId -> prioritize
  29. // Both a and b are either in the userIds array or not, so we'll sort them by their indices
  30. if (aUserIndex !== -1 && bUserIndex !== -1) return aUserIndex - bUserIndex;
  31. // If both are not in the userIds, fallback to alphabetical sorting by name
  32. return a.name.localeCompare(b.name);
  33. });
  34. let query = '';
  35. </script>
  36. <div>
  37. <div class="flex w-full">
  38. <div class="flex flex-1">
  39. <div class=" self-center mr-3">
  40. <Search />
  41. </div>
  42. <input
  43. class=" w-full text-sm pr-4 rounded-r-xl outline-hidden bg-transparent"
  44. bind:value={query}
  45. placeholder={$i18n.t('Search')}
  46. />
  47. </div>
  48. </div>
  49. <div class="mt-3 scrollbar-hidden">
  50. <div class="flex flex-col gap-2.5">
  51. {#if filteredUsers.length > 0}
  52. {#each filteredUsers as user, userIdx (user.id)}
  53. <div class="flex flex-row items-center gap-3 w-full text-sm">
  54. <div class="flex items-center">
  55. <Checkbox
  56. state={userIds.includes(user.id) ? 'checked' : 'unchecked'}
  57. on:change={(e) => {
  58. if (e.detail === 'checked') {
  59. userIds = [...userIds, user.id];
  60. } else {
  61. userIds = userIds.filter((id) => id !== user.id);
  62. }
  63. }}
  64. />
  65. </div>
  66. <div class="flex w-full items-center justify-between">
  67. <Tooltip content={user.email} placement="top-start">
  68. <div class="flex">
  69. <div class=" font-medium self-center">{user.name}</div>
  70. </div>
  71. </Tooltip>
  72. {#if userIds.includes(user.id)}
  73. <Badge type="success" content="member" />
  74. {/if}
  75. </div>
  76. </div>
  77. {/each}
  78. {:else}
  79. <div class="text-gray-500 text-xs text-center py-2 px-10">
  80. {$i18n.t('No users were found.')}
  81. </div>
  82. {/if}
  83. </div>
  84. </div>
  85. </div>