mirror of
https://github.com/open-webui/open-webui.git
synced 2026-10-08 03:08:02 +00:00
refac
This commit is contained in:
parent
0f5a58f5fb
commit
27808f6a02
2 changed files with 85 additions and 46 deletions
|
|
@ -315,7 +315,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="flex-1 mt-1 lg:mt-1 lg:h-[30rem] lg:max-h-[30rem] flex flex-col">
|
||||
<div class="flex-1 min-w-0 mt-1 lg:mt-1 lg:h-[30rem] lg:max-h-[30rem] flex flex-col">
|
||||
<div class="w-full h-full overflow-y-auto scrollbar-hidden">
|
||||
{#if selectedTab == 'general'}
|
||||
<General
|
||||
|
|
@ -343,16 +343,22 @@
|
|||
defaultPermissions={custom ? inheritedPermissions : defaultPermissions}
|
||||
/>
|
||||
{:else if selectedTab == 'users'}
|
||||
<div class="flex gap-3 mb-3 text-sm">
|
||||
<div class="flex flex-wrap items-center gap-x-4 gap-y-1 mb-3">
|
||||
<button
|
||||
type="button"
|
||||
class:underline={membershipTab === 'direct'}
|
||||
aria-pressed={membershipTab === 'direct'}
|
||||
class="py-1 text-xs font-normal transition {membershipTab === 'direct'
|
||||
? 'text-gray-900 dark:text-gray-100'
|
||||
: 'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200'}"
|
||||
on:click={() => (membershipTab = 'direct')}
|
||||
>{$i18n.t('Direct members')}</button
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class:underline={membershipTab === 'inherited'}
|
||||
aria-pressed={membershipTab === 'inherited'}
|
||||
class="py-1 text-xs font-normal transition {membershipTab === 'inherited'
|
||||
? 'text-gray-900 dark:text-gray-100'
|
||||
: 'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200'}"
|
||||
on:click={() => (membershipTab = 'inherited')}
|
||||
>{$i18n.t('Inherited members')}</button
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
<script lang="ts">
|
||||
import { getContext } from 'svelte';
|
||||
import { getGroupMembers } from '$lib/apis/groups';
|
||||
const i18n = getContext<any>('i18n');
|
||||
import { WEBUI_API_BASE_URL } from '$lib/constants';
|
||||
import Pagination from '$lib/components/common/Pagination.svelte';
|
||||
import Spinner from '$lib/components/common/Spinner.svelte';
|
||||
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||
import Search from '$lib/components/icons/Search.svelte';
|
||||
const i18n = getContext<import('svelte/store').Writable<import('i18next').i18n>>('i18n');
|
||||
export let groupId: string;
|
||||
export let groups: import('../Groups.svelte').GroupListItem[] = [];
|
||||
let query = '';
|
||||
|
|
@ -9,54 +14,82 @@
|
|||
$: members = getGroupMembers(localStorage.token, groupId, 'inherited', query, page);
|
||||
</script>
|
||||
|
||||
<div class="space-y-3 text-sm">
|
||||
<p class="text-xs text-gray-500">
|
||||
{$i18n.t('Inherited members are managed in their directly assigned groups.')}
|
||||
</p>
|
||||
<input
|
||||
class="w-full rounded-lg border border-gray-200 dark:border-gray-700 bg-transparent px-2 py-1"
|
||||
aria-label={$i18n.t('Search inherited members')}
|
||||
placeholder={$i18n.t('Search inherited members')}
|
||||
bind:value={query}
|
||||
on:input={() => {
|
||||
page = 1;
|
||||
}}
|
||||
/>
|
||||
<div class="flex w-full min-w-0 flex-col text-sm">
|
||||
<div class="mb-1.5 flex items-center">
|
||||
<div class="self-center mr-3">
|
||||
<Search />
|
||||
</div>
|
||||
<input
|
||||
class="w-full min-w-0 text-sm pr-4 rounded-r-xl outline-hidden bg-transparent"
|
||||
aria-label={$i18n.t('Search inherited members')}
|
||||
placeholder={$i18n.t('Search')}
|
||||
bind:value={query}
|
||||
on:input={() => {
|
||||
page = 1;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{#await members}
|
||||
<p>{$i18n.t('Loading...')}</p>
|
||||
<div class="my-10" role="status" aria-label={$i18n.t('Loading...')}>
|
||||
<Spinner className="size-5" />
|
||||
</div>
|
||||
{:then result}
|
||||
<p class="text-xs text-gray-500">
|
||||
<p class="my-2 text-xs text-gray-500 dark:text-gray-400">
|
||||
{$i18n.t('Inherited members are managed in their directly assigned groups.')}
|
||||
</p>
|
||||
{#if result.items.length > 0}
|
||||
<table class="w-full table-fixed text-left text-sm text-gray-500 dark:text-gray-400">
|
||||
<thead class="text-xs text-gray-800 uppercase dark:text-gray-200">
|
||||
<tr class="border-b-[1.5px] border-gray-50/50 dark:border-gray-800/10">
|
||||
<th scope="col" class="w-1/2 px-2.5 py-1.5">{$i18n.t('Name')}</th>
|
||||
<th scope="col" class="px-2.5 py-1.5">{$i18n.t('Inherited via')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each result.items as member (member.id)}
|
||||
<tr class="text-xs">
|
||||
<td class="px-3 py-1 font-normal text-gray-900 dark:text-white">
|
||||
<Tooltip content={member.email} placement="top-start">
|
||||
<div class="flex min-w-0 items-center gap-2">
|
||||
<img
|
||||
class="size-6 shrink-0 rounded-full object-cover"
|
||||
src={`${WEBUI_API_BASE_URL}/users/${member.id}/profile/image`}
|
||||
alt=""
|
||||
/>
|
||||
<div class="truncate">{member.name}</div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</td>
|
||||
<td class="px-3 py-1">
|
||||
{#each member.via_group_ids as id}
|
||||
<a
|
||||
class="block truncate rounded-sm transition hover:text-gray-700 hover:underline dark:hover:text-gray-200"
|
||||
href={`/admin/users/groups?id=${id}`}
|
||||
title={groups.find((group) => group.id === id)?.path || id}
|
||||
>
|
||||
{groups.find((group) => group.id === id)?.path || id}
|
||||
</a>
|
||||
{/each}
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
{:else}
|
||||
<div class="px-10 py-2 text-center text-xs text-gray-500">
|
||||
{$i18n.t('No inherited members')}
|
||||
</div>
|
||||
{/if}
|
||||
<p class="mt-3 text-xs text-gray-500 dark:text-gray-400">
|
||||
{$i18n.t(
|
||||
'Direct: {{direct}} · Inherited: {{inherited}} · Total: {{effective}}',
|
||||
result.counts
|
||||
)}
|
||||
</p>
|
||||
{#each result.items as member (member.id)}
|
||||
<div class="border-b border-gray-100 dark:border-gray-800 py-2">
|
||||
<div>{member.name} <span class="text-gray-500">{member.email}</span></div>
|
||||
<div class="text-xs text-gray-500">
|
||||
{$i18n.t('Inherited via')}
|
||||
{#each member.via_group_ids as id, index}
|
||||
{index ? ', ' : ''}<a class="underline" href={`/admin/users/groups?id=${id}`}
|
||||
>{groups.find((group) => group.id === id)?.path || id}</a
|
||||
>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{:else}<p class="text-gray-500">{$i18n.t('No inherited members')}</p>{/each}
|
||||
<div class="flex items-center justify-between">
|
||||
<button type="button" disabled={page <= 1} class="disabled:opacity-40" on:click={() => page--}
|
||||
>{$i18n.t('Previous')}</button
|
||||
>
|
||||
<span>{page} / {Math.max(1, Math.ceil(result.total / 30))}</span>
|
||||
<button
|
||||
type="button"
|
||||
disabled={page * 30 >= result.total}
|
||||
class="disabled:opacity-40"
|
||||
on:click={() => page++}>{$i18n.t('Next')}</button
|
||||
>
|
||||
</div>
|
||||
{#if result.total > 30}
|
||||
<Pagination bind:page count={result.total} perPage={30} />
|
||||
{/if}
|
||||
{:catch error}
|
||||
<p role="alert" class="text-red-500">{String(error)}</p>
|
||||
<p role="alert" class="py-4 text-center text-xs text-red-500">{String(error)}</p>
|
||||
{/await}
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue