feat/enh: group share setting

This commit is contained in:
Timothy Jaeryang Baek 2025-11-20 19:12:56 -05:00
parent d1e7957e69
commit 7be750bcbb
7 changed files with 65 additions and 17 deletions

View file

@ -101,6 +101,7 @@ class GroupForm(BaseModel):
name: str name: str
description: str description: str
permissions: Optional[dict] = None permissions: Optional[dict] = None
data: Optional[dict] = None
class UserIdsForm(BaseModel): class UserIdsForm(BaseModel):

View file

@ -31,20 +31,32 @@ router = APIRouter()
@router.get("/", response_model=list[GroupResponse]) @router.get("/", response_model=list[GroupResponse])
async def get_groups(user=Depends(get_verified_user)): async def get_groups(share: Optional[bool] = None, user=Depends(get_verified_user)):
if user.role == "admin": if user.role == "admin":
groups = Groups.get_groups() groups = Groups.get_groups()
else: else:
groups = Groups.get_groups_by_member_id(user.id) groups = Groups.get_groups_by_member_id(user.id)
return [ group_list = []
GroupResponse(
**group.model_dump(), for group in groups:
member_count=Groups.get_group_member_count_by_id(group.id), if share is not None:
# Check if the group has data and a config with share key
if (
group.data
and "share" in group.data.get("config", {})
and group.data["config"]["share"] != share
):
continue
group_list.append(
GroupResponse(
**group.model_dump(),
member_count=Groups.get_group_member_count_by_id(group.id),
)
) )
for group in groups
if group return group_list
]
############################ ############################

View file

@ -31,10 +31,15 @@ export const createNewGroup = async (token: string, group: object) => {
return res; return res;
}; };
export const getGroups = async (token: string = '') => { export const getGroups = async (token: string = '', share?: boolean) => {
let error = null; let error = null;
const res = await fetch(`${WEBUI_API_BASE_URL}/groups/`, { const searchParams = new URLSearchParams();
if (share !== undefined) {
searchParams.append('share', String(share));
}
const res = await fetch(`${WEBUI_API_BASE_URL}/groups/?${searchParams.toString()}`, {
method: 'GET', method: 'GET',
headers: { headers: {
Accept: 'application/json', Accept: 'application/json',

View file

@ -34,7 +34,7 @@
export let name = ''; export let name = '';
export let description = ''; export let description = '';
export let config = {}; export let data = {};
export let permissions = { export let permissions = {
workspace: { workspace: {
@ -98,6 +98,7 @@
const group = { const group = {
name, name,
description, description,
data,
permissions permissions
}; };
@ -112,7 +113,7 @@
name = group.name; name = group.name;
description = group.description; description = group.description;
permissions = group?.permissions ?? {}; permissions = group?.permissions ?? {};
config = group?.data?.config ?? {}; data = group?.data ?? {};
userCount = group?.member_count ?? 0; userCount = group?.member_count ?? 0;
} }
@ -246,7 +247,7 @@
<General <General
bind:name bind:name
bind:description bind:description
bind:config bind:data
{edit} {edit}
onDelete={() => { onDelete={() => {
showDeleteConfirmDialog = true; showDeleteConfirmDialog = true;

View file

@ -2,13 +2,14 @@
import { getContext } from 'svelte'; import { getContext } from 'svelte';
import Textarea from '$lib/components/common/Textarea.svelte'; import Textarea from '$lib/components/common/Textarea.svelte';
import Tooltip from '$lib/components/common/Tooltip.svelte'; import Tooltip from '$lib/components/common/Tooltip.svelte';
import Switch from '$lib/components/common/Switch.svelte';
const i18n = getContext('i18n'); const i18n = getContext('i18n');
export let name = ''; export let name = '';
export let color = ''; export let color = '';
export let description = ''; export let description = '';
export let config = {}; export let data = {};
export let edit = false; export let edit = false;
export let onDelete: Function = () => {}; export let onDelete: Function = () => {};
@ -64,6 +65,34 @@
</div> </div>
</div> </div>
<hr class="border-gray-50 dark:border-gray-850 my-1" />
<div class="flex flex-col w-full mt-2">
<div class=" mb-1 text-xs text-gray-500">{$i18n.t('Setting')}</div>
<div>
<div class=" flex w-full justify-between">
<div class=" self-center text-xs">
{$i18n.t('Allow Group Sharing')}
</div>
<div class="flex items-center gap-2 p-1">
<Switch
tooltip={true}
state={data?.config?.share ?? true}
on:change={(e) => {
if (data?.config?.share) {
data.config.share = e.detail;
} else {
data.config = { ...(data?.config ?? {}), share: e.detail };
}
}}
/>
</div>
</div>
</div>
</div>
{#if edit} {#if edit}
<div class="flex flex-col w-full mt-2"> <div class="flex flex-col w-full mt-2">
<div class=" mb-0.5 text-xs text-gray-500">{$i18n.t('Actions')}</div> <div class=" mb-0.5 text-xs text-gray-500">{$i18n.t('Actions')}</div>

View file

@ -10,7 +10,7 @@
import Pencil from '$lib/components/icons/Pencil.svelte'; import Pencil from '$lib/components/icons/Pencil.svelte';
import User from '$lib/components/icons/User.svelte'; import User from '$lib/components/icons/User.svelte';
import UserCircleSolid from '$lib/components/icons/UserCircleSolid.svelte'; import UserCircleSolid from '$lib/components/icons/UserCircleSolid.svelte';
import GroupModal from './EditGroupModal.svelte'; import EditGroupModal from './EditGroupModal.svelte';
export let group = { export let group = {
name: 'Admins', name: 'Admins',
@ -54,7 +54,7 @@
}); });
</script> </script>
<GroupModal <EditGroupModal
bind:show={showEdit} bind:show={showEdit}
edit edit
{group} {group}

View file

@ -42,7 +42,7 @@
}; };
onMount(async () => { onMount(async () => {
groups = await getGroups(localStorage.token); groups = await getGroups(localStorage.token, true);
if (accessControl === null) { if (accessControl === null) {
initPublicAccess(); initPublicAccess();