refac/enh: chat controls permissions

This commit is contained in:
Timothy Jaeryang Baek 2025-07-31 18:58:58 +04:00
parent 84289b9a8d
commit 708e0ed05e
7 changed files with 127 additions and 78 deletions

View file

@ -1143,10 +1143,18 @@ USER_PERMISSIONS_CHAT_CONTROLS = (
os.environ.get("USER_PERMISSIONS_CHAT_CONTROLS", "True").lower() == "true" os.environ.get("USER_PERMISSIONS_CHAT_CONTROLS", "True").lower() == "true"
) )
USER_PERMISSIONS_CHAT_VALVES = (
os.environ.get("USER_PERMISSIONS_CHAT_VALVES", "True").lower() == "true"
)
USER_PERMISSIONS_CHAT_SYSTEM_PROMPT = ( USER_PERMISSIONS_CHAT_SYSTEM_PROMPT = (
os.environ.get("USER_PERMISSIONS_CHAT_SYSTEM_PROMPT", "True").lower() == "true" os.environ.get("USER_PERMISSIONS_CHAT_SYSTEM_PROMPT", "True").lower() == "true"
) )
USER_PERMISSIONS_CHAT_PARAMS = (
os.environ.get("USER_PERMISSIONS_CHAT_PARAMS", "True").lower() == "true"
)
USER_PERMISSIONS_CHAT_FILE_UPLOAD = ( USER_PERMISSIONS_CHAT_FILE_UPLOAD = (
os.environ.get("USER_PERMISSIONS_CHAT_FILE_UPLOAD", "True").lower() == "true" os.environ.get("USER_PERMISSIONS_CHAT_FILE_UPLOAD", "True").lower() == "true"
) )
@ -1232,7 +1240,9 @@ DEFAULT_USER_PERMISSIONS = {
}, },
"chat": { "chat": {
"controls": USER_PERMISSIONS_CHAT_CONTROLS, "controls": USER_PERMISSIONS_CHAT_CONTROLS,
"valves": USER_PERMISSIONS_CHAT_VALVES,
"system_prompt": USER_PERMISSIONS_CHAT_SYSTEM_PROMPT, "system_prompt": USER_PERMISSIONS_CHAT_SYSTEM_PROMPT,
"params": USER_PERMISSIONS_CHAT_PARAMS,
"file_upload": USER_PERMISSIONS_CHAT_FILE_UPLOAD, "file_upload": USER_PERMISSIONS_CHAT_FILE_UPLOAD,
"delete": USER_PERMISSIONS_CHAT_DELETE, "delete": USER_PERMISSIONS_CHAT_DELETE,
"edit": USER_PERMISSIONS_CHAT_EDIT, "edit": USER_PERMISSIONS_CHAT_EDIT,

View file

@ -134,7 +134,9 @@ class SharingPermissions(BaseModel):
class ChatPermissions(BaseModel): class ChatPermissions(BaseModel):
controls: bool = True controls: bool = True
valves: bool = True
system_prompt: bool = True system_prompt: bool = True
params: bool = True
file_upload: bool = True file_upload: bool = True
delete: bool = True delete: bool = True
edit: bool = True edit: bool = True

View file

@ -66,7 +66,9 @@
}, },
chat: { chat: {
controls: true, controls: true,
valves: true,
system_prompt: true, system_prompt: true,
params: true,
file_upload: true, file_upload: true,
delete: true, delete: true,
edit: true, edit: true,

View file

@ -48,10 +48,20 @@
}, },
chat: { chat: {
controls: true, controls: true,
valves: true,
system_prompt: true,
params: true,
file_upload: true, file_upload: true,
delete: true, delete: true,
edit: true, edit: true,
temporary: true share: true,
export: true,
stt: true,
tts: true,
call: true,
multiple_models: true,
temporary: true,
temporary_enforced: false
}, },
features: { features: {
direct_tool_servers: false, direct_tool_servers: false,

View file

@ -21,6 +21,9 @@
}, },
chat: { chat: {
controls: true, controls: true,
valves: true,
system_prompt: true,
params: true,
file_upload: true, file_upload: true,
delete: true, delete: true,
edit: true, edit: true,
@ -263,6 +266,14 @@
<Switch bind:state={permissions.chat.controls} /> <Switch bind:state={permissions.chat.controls} />
</div> </div>
<div class=" flex w-full justify-between my-2 pr-2">
<div class=" self-center text-xs font-medium">
{$i18n.t('Allow Chat Valves')}
</div>
<Switch bind:state={permissions.chat.valves} />
</div>
<div class=" flex w-full justify-between my-2 pr-2"> <div class=" flex w-full justify-between my-2 pr-2">
<div class=" self-center text-xs font-medium"> <div class=" self-center text-xs font-medium">
{$i18n.t('Allow Chat System Prompt')} {$i18n.t('Allow Chat System Prompt')}
@ -271,6 +282,14 @@
<Switch bind:state={permissions.chat.system_prompt} /> <Switch bind:state={permissions.chat.system_prompt} />
</div> </div>
<div class=" flex w-full justify-between my-2 pr-2">
<div class=" self-center text-xs font-medium">
{$i18n.t('Allow Chat Params')}
</div>
<Switch bind:state={permissions.chat.params} />
</div>
<div class=" flex w-full justify-between my-2 pr-2"> <div class=" flex w-full justify-between my-2 pr-2">
<div class=" self-center text-xs font-medium"> <div class=" self-center text-xs font-medium">
{$i18n.t('Allow Chat Delete')} {$i18n.t('Allow Chat Delete')}

View file

@ -30,70 +30,74 @@
</button> </button>
</div> </div>
<div class=" dark:text-gray-200 text-sm font-primary py-0.5 px-0.5"> {#if $user?.role === 'admin' || ($user?.permissions.chat?.controls ?? true)}
{#if chatFiles.length > 0} <div class=" dark:text-gray-200 text-sm font-primary py-0.5 px-0.5">
<Collapsible title={$i18n.t('Files')} open={true} buttonClassName="w-full"> {#if chatFiles.length > 0}
<div class="flex flex-col gap-1 mt-1.5" slot="content"> <Collapsible title={$i18n.t('Files')} open={true} buttonClassName="w-full">
{#each chatFiles as file, fileIdx} <div class="flex flex-col gap-1 mt-1.5" slot="content">
<FileItem {#each chatFiles as file, fileIdx}
className="w-full" <FileItem
item={file} className="w-full"
edit={true} item={file}
url={file?.url ? file.url : null} edit={true}
name={file.name} url={file?.url ? file.url : null}
type={file.type} name={file.name}
size={file?.size} type={file.type}
dismissible={true} size={file?.size}
on:dismiss={() => { dismissible={true}
// Remove the file from the chatFiles array on:dismiss={() => {
// Remove the file from the chatFiles array
chatFiles.splice(fileIdx, 1); chatFiles.splice(fileIdx, 1);
chatFiles = chatFiles; chatFiles = chatFiles;
}} }}
on:click={() => { on:click={() => {
console.log(file); console.log(file);
}} }}
/> />
{/each} {/each}
</div>
</Collapsible>
<hr class="my-2 border-gray-50 dark:border-gray-700/10" />
{/if}
<Collapsible bind:open={showValves} title={$i18n.t('Valves')} buttonClassName="w-full">
<div class="text-sm" slot="content">
<Valves show={showValves} />
</div>
</Collapsible>
{#if $user?.role === 'admin' || ($user?.permissions.chat?.system_prompt ?? true)}
<hr class="my-2 border-gray-50 dark:border-gray-700/10" />
<Collapsible title={$i18n.t('System Prompt')} open={true} buttonClassName="w-full">
<div class="" slot="content">
<textarea
bind:value={params.system}
class="w-full text-xs outline-hidden resize-vertical {$settings.highContrastMode
? 'border-2 border-gray-300 dark:border-gray-700 rounded-lg bg-gray-50 dark:bg-gray-800 p-2.5'
: 'py-1.5 bg-transparent'}"
rows="4"
placeholder={$i18n.t('Enter system prompt')}
/>
</div>
</Collapsible>
{/if}
{#if $user?.role === 'admin' || ($user?.permissions.chat?.controls ?? true)}
<hr class="my-2 border-gray-50 dark:border-gray-700/10" />
<Collapsible title={$i18n.t('Advanced Params')} open={true} buttonClassName="w-full">
<div class="text-sm mt-1.5" slot="content">
<div>
<AdvancedParams admin={$user?.role === 'admin'} custom={true} bind:params />
</div> </div>
</div> </Collapsible>
</Collapsible>
{/if} <hr class="my-2 border-gray-50 dark:border-gray-700/10" />
</div> {/if}
{#if $user?.role === 'admin' || ($user?.permissions.chat?.valves ?? true)}
<Collapsible bind:open={showValves} title={$i18n.t('Valves')} buttonClassName="w-full">
<div class="text-sm" slot="content">
<Valves show={showValves} />
</div>
</Collapsible>
{/if}
{#if $user?.role === 'admin' || ($user?.permissions.chat?.system_prompt ?? true)}
<hr class="my-2 border-gray-50 dark:border-gray-700/10" />
<Collapsible title={$i18n.t('System Prompt')} open={true} buttonClassName="w-full">
<div class="" slot="content">
<textarea
bind:value={params.system}
class="w-full text-xs outline-hidden resize-vertical {$settings.highContrastMode
? 'border-2 border-gray-300 dark:border-gray-700 rounded-lg bg-gray-50 dark:bg-gray-800 p-2.5'
: 'py-1.5 bg-transparent'}"
rows="4"
placeholder={$i18n.t('Enter system prompt')}
/>
</div>
</Collapsible>
{/if}
{#if $user?.role === 'admin' || ($user?.permissions.chat?.params ?? true)}
<hr class="my-2 border-gray-50 dark:border-gray-700/10" />
<Collapsible title={$i18n.t('Advanced Params')} open={true} buttonClassName="w-full">
<div class="text-sm mt-1.5" slot="content">
<div>
<AdvancedParams admin={$user?.role === 'admin'} custom={true} bind:params />
</div>
</div>
</Collapsible>
{/if}
</div>
{/if}
</div> </div>

View file

@ -151,19 +151,21 @@
</Menu> </Menu>
{/if} {/if}
<Tooltip content={$i18n.t('Controls')}> {#if $user?.role === 'admin' || ($user?.permissions.chat?.controls ?? true)}
<button <Tooltip content={$i18n.t('Controls')}>
class=" flex cursor-pointer px-2 py-2 rounded-xl hover:bg-gray-50 dark:hover:bg-gray-850 transition" <button
on:click={async () => { class=" flex cursor-pointer px-2 py-2 rounded-xl hover:bg-gray-50 dark:hover:bg-gray-850 transition"
await showControls.set(!$showControls); on:click={async () => {
}} await showControls.set(!$showControls);
aria-label="Controls" }}
> aria-label="Controls"
<div class=" m-auto self-center"> >
<AdjustmentsHorizontal className=" size-5" strokeWidth="0.5" /> <div class=" m-auto self-center">
</div> <AdjustmentsHorizontal className=" size-5" strokeWidth="0.5" />
</button> </div>
</Tooltip> </button>
</Tooltip>
{/if}
{#if $mobile} {#if $mobile}
<Tooltip content={$i18n.t('New Chat')}> <Tooltip content={$i18n.t('New Chat')}>