mirror of
https://github.com/open-webui/open-webui.git
synced 2026-10-10 03:27:57 +00:00
refac
This commit is contained in:
parent
db1ca1afab
commit
b3ce7de8d3
12 changed files with 199 additions and 7 deletions
|
|
@ -1,4 +1,6 @@
|
|||
<script lang="ts">
|
||||
import WorkspaceAccessModal from './common/WorkspaceAccessModal.svelte';
|
||||
let accessModal: WorkspaceAccessModal;
|
||||
import dayjs from 'dayjs';
|
||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
dayjs.extend(relativeTime);
|
||||
|
|
@ -296,6 +298,8 @@
|
|||
});
|
||||
</script>
|
||||
|
||||
<WorkspaceAccessModal bind:this={accessModal} resourceType="knowledge" onUpdated={init} />
|
||||
|
||||
<svelte:head>
|
||||
<!-- LICENSE covers this Open WebUI browser-title identifier.
|
||||
Do not alter, remove, obscure, or replace it except as LICENSE permits:
|
||||
|
|
@ -524,6 +528,7 @@
|
|||
{#if item?.write_access || $user?.role === 'admin'}
|
||||
<div class="ml-2 flex shrink-0 flex-row items-center self-center">
|
||||
<ItemMenu
|
||||
accessHandler={() => accessModal.open(item.id)}
|
||||
onExport={$user?.role === 'admin'
|
||||
? () => {
|
||||
exportHandler(item);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script lang="ts">
|
||||
import LockClosed from '$lib/components/icons/LockClosed.svelte';
|
||||
import { getContext, createEventDispatcher } from 'svelte';
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
|
|
@ -9,9 +10,10 @@
|
|||
import Download from '$lib/components/icons/Download.svelte';
|
||||
import EllipsisHorizontal from '$lib/components/icons/EllipsisHorizontal.svelte';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
const i18n = getContext<typeof import('$lib/i18n').default>('i18n');
|
||||
|
||||
export let onExport: null | Function = null;
|
||||
export let accessHandler: (() => void) | null = null;
|
||||
export let onClose: Function = () => {};
|
||||
|
||||
let show = false;
|
||||
|
|
@ -50,6 +52,20 @@
|
|||
|
||||
<div slot="content">
|
||||
<DropdownMenu className="min-w-[10.625rem]">
|
||||
{#if accessHandler}
|
||||
<button
|
||||
type="button"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[0.8125rem] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
accessHandler?.();
|
||||
closeMenu();
|
||||
}}
|
||||
>
|
||||
<LockClosed className="size-3.5" />
|
||||
<div class="flex items-center">{$i18n.t('Access')}</div>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
{#if onExport}
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[0.8125rem] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
<script lang="ts">
|
||||
import WorkspaceAccessModal from './common/WorkspaceAccessModal.svelte';
|
||||
let accessModal: WorkspaceAccessModal;
|
||||
import dayjs from 'dayjs';
|
||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
import { toast } from 'svelte-sonner';
|
||||
|
|
@ -506,6 +508,8 @@
|
|||
});
|
||||
</script>
|
||||
|
||||
<WorkspaceAccessModal bind:this={accessModal} resourceType="models" onUpdated={getModelList} />
|
||||
|
||||
<svelte:head>
|
||||
<!-- LICENSE covers this Open WebUI browser-title identifier.
|
||||
Do not alter, remove, obscure, or replace it except as LICENSE permits:
|
||||
|
|
@ -924,6 +928,7 @@
|
|||
{:else}
|
||||
<div class="flex shrink-0 flex-row items-center gap-1 self-center">
|
||||
<ModelMenu
|
||||
accessHandler={() => accessModal.open(model.id)}
|
||||
user={$user}
|
||||
{model}
|
||||
writeAccess={model.write_access}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script lang="ts">
|
||||
import LockClosed from '$lib/components/icons/LockClosed.svelte';
|
||||
import { getContext } from 'svelte';
|
||||
|
||||
import Dropdown from '$lib/components/common/Dropdown.svelte';
|
||||
|
|
@ -33,6 +34,7 @@
|
|||
export let hideHandler: Function;
|
||||
export let pinModelHandler: Function;
|
||||
export let deleteHandler: Function;
|
||||
export let accessHandler: (() => void) | null = null;
|
||||
export let onClose: Function;
|
||||
|
||||
export let writeAccess: boolean = true;
|
||||
|
|
@ -80,6 +82,18 @@
|
|||
<div class="flex items-center">{$i18n.t('Edit')}</div>
|
||||
</button>
|
||||
{/if}
|
||||
{#if accessHandler && writeAccess}
|
||||
<button
|
||||
type="button"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[0.8125rem] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
runAndClose(() => accessHandler?.());
|
||||
}}
|
||||
>
|
||||
<LockClosed className="size-3.5" />
|
||||
<div class="flex items-center">{$i18n.t('Access')}</div>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
{#if writeAccess}
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
<script lang="ts">
|
||||
import WorkspaceAccessModal from './common/WorkspaceAccessModal.svelte';
|
||||
let accessModal: WorkspaceAccessModal;
|
||||
import dayjs from 'dayjs';
|
||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
import { toast } from 'svelte-sonner';
|
||||
|
|
@ -375,6 +377,8 @@
|
|||
});
|
||||
</script>
|
||||
|
||||
<WorkspaceAccessModal bind:this={accessModal} resourceType="prompts" onUpdated={getPromptList} />
|
||||
|
||||
<svelte:head>
|
||||
<!-- LICENSE covers this Open WebUI browser-title identifier.
|
||||
Do not alter, remove, obscure, or replace it except as LICENSE permits:
|
||||
|
|
@ -688,6 +692,7 @@
|
|||
|
||||
<div class="ml-0.5 flex shrink-0 flex-row items-center gap-1.5 self-center">
|
||||
<PromptMenu
|
||||
accessHandler={() => accessModal.open(prompt.id)}
|
||||
writeAccess={prompt.write_access}
|
||||
show={openPromptMenuId === prompt.id}
|
||||
editHandler={() => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script lang="ts">
|
||||
import LockClosed from '$lib/components/icons/LockClosed.svelte';
|
||||
import { getContext } from 'svelte';
|
||||
import { config, user } from '$lib/stores';
|
||||
|
||||
|
|
@ -10,7 +11,7 @@
|
|||
import DocumentDuplicate from '$lib/components/icons/DocumentDuplicate.svelte';
|
||||
import Download from '$lib/components/icons/Download.svelte';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
const i18n = getContext<typeof import('$lib/i18n').default>('i18n');
|
||||
|
||||
export let writeAccess = true;
|
||||
|
||||
|
|
@ -19,6 +20,7 @@
|
|||
export let cloneHandler: Function;
|
||||
export let exportHandler: Function;
|
||||
export let deleteHandler: Function;
|
||||
export let accessHandler: (() => void) | null = null;
|
||||
export let onClose: Function;
|
||||
|
||||
export let show = false;
|
||||
|
|
@ -69,6 +71,19 @@
|
|||
|
||||
<div class="flex items-center">{$i18n.t('Edit')}</div>
|
||||
</button>
|
||||
{#if accessHandler && writeAccess}
|
||||
<button
|
||||
type="button"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[0.8125rem] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
accessHandler?.();
|
||||
closeMenu();
|
||||
}}
|
||||
>
|
||||
<LockClosed className="size-3.5" />
|
||||
<div class="flex items-center">{$i18n.t('Access')}</div>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
{#if $config.features.enable_community_sharing}
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
<script lang="ts">
|
||||
import WorkspaceAccessModal from './common/WorkspaceAccessModal.svelte';
|
||||
let accessModal: WorkspaceAccessModal;
|
||||
import { resolveLocalizedResource } from '$lib/utils/localizedContent';
|
||||
import dayjs from 'dayjs';
|
||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
|
|
@ -282,6 +284,8 @@
|
|||
});
|
||||
</script>
|
||||
|
||||
<WorkspaceAccessModal bind:this={accessModal} resourceType="skills" onUpdated={loadSkillItems} />
|
||||
|
||||
<svelte:head>
|
||||
<!-- LICENSE covers this Open WebUI browser-title identifier.
|
||||
Do not alter, remove, obscure, or replace it except as LICENSE permits:
|
||||
|
|
@ -535,6 +539,7 @@
|
|||
{:else}
|
||||
<div class="flex shrink-0 flex-row items-center gap-1.5 self-center">
|
||||
<SkillMenu
|
||||
accessHandler={() => accessModal.open(skill.id)}
|
||||
show={openSkillMenuId === skill.id}
|
||||
editHandler={() => {
|
||||
goto(`/workspace/skills/edit?id=${encodeURIComponent(skill.id)}`);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script lang="ts">
|
||||
import LockClosed from '$lib/components/icons/LockClosed.svelte';
|
||||
import { getContext } from 'svelte';
|
||||
|
||||
import Dropdown from '$lib/components/common/Dropdown.svelte';
|
||||
|
|
@ -9,12 +10,13 @@
|
|||
import Download from '$lib/components/icons/Download.svelte';
|
||||
import { user } from '$lib/stores';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
const i18n = getContext<typeof import('$lib/i18n').default>('i18n');
|
||||
|
||||
export let editHandler: Function;
|
||||
export let cloneHandler: Function;
|
||||
export let exportHandler: Function;
|
||||
export let deleteHandler: Function;
|
||||
export let accessHandler: (() => void) | null = null;
|
||||
export let onClose: Function;
|
||||
|
||||
export let show = false;
|
||||
|
|
@ -63,6 +65,19 @@
|
|||
|
||||
<div class="flex items-center">{$i18n.t('Edit')}</div>
|
||||
</button>
|
||||
{#if accessHandler}
|
||||
<button
|
||||
type="button"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[0.8125rem] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
accessHandler?.();
|
||||
closeMenu();
|
||||
}}
|
||||
>
|
||||
<LockClosed className="size-3.5" />
|
||||
<div class="flex items-center">{$i18n.t('Access')}</div>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<button
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[0.8125rem] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
<script lang="ts">
|
||||
import WorkspaceAccessModal from './common/WorkspaceAccessModal.svelte';
|
||||
let accessModal: WorkspaceAccessModal;
|
||||
import { resolveLocalizedResource } from '$lib/utils/localizedContent';
|
||||
import dayjs from 'dayjs';
|
||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
|
|
@ -294,6 +296,8 @@
|
|||
});
|
||||
</script>
|
||||
|
||||
<WorkspaceAccessModal bind:this={accessModal} resourceType="tools" onUpdated={init} />
|
||||
|
||||
<svelte:head>
|
||||
<!-- LICENSE covers this Open WebUI browser-title identifier.
|
||||
Do not alter, remove, obscure, or replace it except as LICENSE permits:
|
||||
|
|
@ -587,6 +591,7 @@
|
|||
</Tooltip>
|
||||
|
||||
<ToolMenu
|
||||
accessHandler={() => accessModal.open(tool.id)}
|
||||
show={openToolMenuId === tool.id}
|
||||
editHandler={() => {
|
||||
goto(`/workspace/tools/edit?id=${encodeURIComponent(tool.id)}`);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script lang="ts">
|
||||
import LockClosed from '$lib/components/icons/LockClosed.svelte';
|
||||
import { getContext } from 'svelte';
|
||||
|
||||
import Dropdown from '$lib/components/common/Dropdown.svelte';
|
||||
|
|
@ -11,13 +12,14 @@
|
|||
import Download from '$lib/components/icons/Download.svelte';
|
||||
import { config, user } from '$lib/stores';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
const i18n = getContext<typeof import('$lib/i18n').default>('i18n');
|
||||
|
||||
export let editHandler: Function;
|
||||
export let shareHandler: Function;
|
||||
export let cloneHandler: Function;
|
||||
export let exportHandler: Function;
|
||||
export let deleteHandler: Function;
|
||||
export let accessHandler: (() => void) | null = null;
|
||||
export let onClose: Function;
|
||||
|
||||
export let show = false;
|
||||
|
|
@ -67,6 +69,19 @@
|
|||
|
||||
<div class="flex items-center">{$i18n.t('Edit')}</div>
|
||||
</button>
|
||||
{#if accessHandler}
|
||||
<button
|
||||
type="button"
|
||||
class="select-none flex h-[1.6875rem] w-full cursor-pointer items-center gap-2 rounded-xl bg-transparent px-2 text-[0.8125rem] hover:text-gray-900 dark:hover:text-gray-100"
|
||||
on:click={() => {
|
||||
accessHandler?.();
|
||||
closeMenu();
|
||||
}}
|
||||
>
|
||||
<LockClosed className="size-3.5" />
|
||||
<div class="flex items-center">{$i18n.t('Access')}</div>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
{#if $config.features.enable_community_sharing}
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { getContext } from 'svelte';
|
||||
const i18n = getContext('i18n');
|
||||
const i18n = getContext<typeof import('$lib/i18n').default>('i18n');
|
||||
|
||||
import Modal from '$lib/components/common/Modal.svelte';
|
||||
import AccessControl from './AccessControl.svelte';
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
};
|
||||
|
||||
export let show = false;
|
||||
export let disabled = false;
|
||||
export let accessGrants: AccessGrant[] = [];
|
||||
export let accessControl: any = undefined;
|
||||
export let accessRoles = ['read'];
|
||||
|
|
@ -24,7 +25,7 @@
|
|||
export let shareUsers = true;
|
||||
export let allowGroups = true;
|
||||
|
||||
export let onChange = () => {};
|
||||
export let onChange: (grants: AccessGrant[]) => void | Promise<void> = () => {};
|
||||
</script>
|
||||
|
||||
<Modal size="sm" bind:show>
|
||||
|
|
@ -43,7 +44,7 @@
|
|||
</button>
|
||||
</div>
|
||||
|
||||
<div class="w-full px-4 pb-3 dark:text-white">
|
||||
<div class="w-full px-4 pb-3 dark:text-white" inert={disabled} aria-busy={disabled}>
|
||||
<AccessControl
|
||||
bind:accessGrants
|
||||
bind:accessControl
|
||||
|
|
|
|||
|
|
@ -0,0 +1,91 @@
|
|||
<script lang="ts">
|
||||
import { getContext } from 'svelte';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { user } from '$lib/stores';
|
||||
import { getModelById, updateModelAccessGrants } from '$lib/apis/models';
|
||||
import { getKnowledgeById, updateKnowledgeAccessGrants } from '$lib/apis/knowledge';
|
||||
import { getPromptById, updatePromptAccessGrants } from '$lib/apis/prompts';
|
||||
import { getSkillById, updateSkillAccessGrants } from '$lib/apis/skills';
|
||||
import { getToolById, updateToolAccessGrants } from '$lib/apis/tools';
|
||||
import AccessControlModal from './AccessControlModal.svelte';
|
||||
|
||||
export let resourceType: 'models' | 'knowledge' | 'prompts' | 'skills' | 'tools';
|
||||
export let onUpdated: () => void | Promise<void> = () => {};
|
||||
const i18n = getContext<any>('i18n');
|
||||
const loaders = {
|
||||
models: getModelById,
|
||||
knowledge: getKnowledgeById,
|
||||
prompts: getPromptById,
|
||||
skills: getSkillById,
|
||||
tools: getToolById
|
||||
};
|
||||
const savers = {
|
||||
knowledge: updateKnowledgeAccessGrants,
|
||||
prompts: updatePromptAccessGrants,
|
||||
skills: updateSkillAccessGrants,
|
||||
tools: updateToolAccessGrants
|
||||
};
|
||||
let show = false;
|
||||
let saving = false;
|
||||
let resource: any = null;
|
||||
let accessGrants: any[] = [];
|
||||
let savedGrants: any[] = [];
|
||||
let requestId = 0;
|
||||
const reportError = (error: any) => toast.error(`${error?.detail ?? error}`);
|
||||
|
||||
export const open = async (id: string) => {
|
||||
const request = ++requestId;
|
||||
show = false;
|
||||
try {
|
||||
const result = await loaders[resourceType](localStorage.token, id);
|
||||
if (request !== requestId) return;
|
||||
resource = result;
|
||||
accessGrants = structuredClone(result.access_grants ?? []);
|
||||
savedGrants = structuredClone(accessGrants);
|
||||
saving = false;
|
||||
show = true;
|
||||
} catch (error) {
|
||||
if (request === requestId) reportError(error);
|
||||
}
|
||||
};
|
||||
|
||||
const save = async (grants: any[]) => {
|
||||
if (saving || !resource) return;
|
||||
const request = requestId;
|
||||
saving = true;
|
||||
try {
|
||||
const updated =
|
||||
resourceType === 'models'
|
||||
? await updateModelAccessGrants(localStorage.token, resource.id, resource.name, grants)
|
||||
: await savers[resourceType](localStorage.token, resource.id, grants);
|
||||
if (request === requestId) {
|
||||
accessGrants = structuredClone(updated.access_grants ?? []);
|
||||
savedGrants = structuredClone(accessGrants);
|
||||
}
|
||||
toast.success($i18n.t('Saved'));
|
||||
} catch (error) {
|
||||
if (request === requestId) accessGrants = structuredClone(savedGrants);
|
||||
reportError(error);
|
||||
return;
|
||||
} finally {
|
||||
if (request === requestId) saving = false;
|
||||
}
|
||||
try {
|
||||
await onUpdated();
|
||||
} catch (error) {
|
||||
reportError(error);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<AccessControlModal
|
||||
bind:show
|
||||
bind:accessGrants
|
||||
disabled={saving}
|
||||
accessRoles={resourceType === 'models' && !resource?.base_model_id ? ['read'] : ['read', 'write']}
|
||||
share={$user?.permissions?.sharing?.[resourceType] || $user?.role === 'admin'}
|
||||
sharePublic={$user?.permissions?.sharing?.[`public_${resourceType}`] || $user?.role === 'admin'}
|
||||
shareUsers={($user?.permissions?.access_grants?.allow_users ?? true) || $user?.role === 'admin'}
|
||||
allowGroups={($user?.permissions?.access_grants?.allow_groups ?? true) || $user?.role === 'admin'}
|
||||
onChange={save}
|
||||
/>
|
||||
Loading…
Add table
Reference in a new issue