mirror of
https://github.com/open-webui/open-webui
synced 2024-11-22 08:07:55 +00:00
refac: frontend
This commit is contained in:
parent
2ab5b2fd71
commit
d9dc04f1a1
@ -1,35 +1,7 @@
|
|||||||
import { WEBUI_API_BASE_URL } from '$lib/constants';
|
import { WEBUI_API_BASE_URL } from '$lib/constants';
|
||||||
|
|
||||||
export const addNewModel = async (token: string, model: object) => {
|
|
||||||
let error = null;
|
|
||||||
|
|
||||||
const res = await fetch(`${WEBUI_API_BASE_URL}/models/add`, {
|
export const getWorkspaceModels = async (token: string = '') => {
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
Accept: 'application/json',
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
authorization: `Bearer ${token}`
|
|
||||||
},
|
|
||||||
body: JSON.stringify(model)
|
|
||||||
})
|
|
||||||
.then(async (res) => {
|
|
||||||
if (!res.ok) throw await res.json();
|
|
||||||
return res.json();
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
error = err.detail;
|
|
||||||
console.log(err);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getModelInfos = async (token: string = '') => {
|
|
||||||
let error = null;
|
let error = null;
|
||||||
|
|
||||||
const res = await fetch(`${WEBUI_API_BASE_URL}/models`, {
|
const res = await fetch(`${WEBUI_API_BASE_URL}/models`, {
|
||||||
@ -60,13 +32,46 @@ export const getModelInfos = async (token: string = '') => {
|
|||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const createNewModel = async (token: string, model: object) => {
|
||||||
|
let error = null;
|
||||||
|
|
||||||
|
const res = await fetch(`${WEBUI_API_BASE_URL}/models/create`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
authorization: `Bearer ${token}`
|
||||||
|
},
|
||||||
|
body: JSON.stringify(model)
|
||||||
|
})
|
||||||
|
.then(async (res) => {
|
||||||
|
if (!res.ok) throw await res.json();
|
||||||
|
return res.json();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
error = err.detail;
|
||||||
|
console.log(err);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const getModelById = async (token: string, id: string) => {
|
export const getModelById = async (token: string, id: string) => {
|
||||||
let error = null;
|
let error = null;
|
||||||
|
|
||||||
const searchParams = new URLSearchParams();
|
const searchParams = new URLSearchParams();
|
||||||
searchParams.append('id', id);
|
searchParams.append('id', id);
|
||||||
|
|
||||||
const res = await fetch(`${WEBUI_API_BASE_URL}/models?${searchParams.toString()}`, {
|
const res = await fetch(`${WEBUI_API_BASE_URL}/models/id/${id}`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
Accept: 'application/json',
|
Accept: 'application/json',
|
||||||
@ -101,7 +106,7 @@ export const updateModelById = async (token: string, id: string, model: object)
|
|||||||
const searchParams = new URLSearchParams();
|
const searchParams = new URLSearchParams();
|
||||||
searchParams.append('id', id);
|
searchParams.append('id', id);
|
||||||
|
|
||||||
const res = await fetch(`${WEBUI_API_BASE_URL}/models/update?${searchParams.toString()}`, {
|
const res = await fetch(`${WEBUI_API_BASE_URL}/models/id/${id}/update`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Accept: 'application/json',
|
Accept: 'application/json',
|
||||||
@ -137,7 +142,7 @@ export const deleteModelById = async (token: string, id: string) => {
|
|||||||
const searchParams = new URLSearchParams();
|
const searchParams = new URLSearchParams();
|
||||||
searchParams.append('id', id);
|
searchParams.append('id', id);
|
||||||
|
|
||||||
const res = await fetch(`${WEBUI_API_BASE_URL}/models/delete?${searchParams.toString()}`, {
|
const res = await fetch(`${WEBUI_API_BASE_URL}/models/id/${id}/delete`, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
headers: {
|
headers: {
|
||||||
Accept: 'application/json',
|
Accept: 'application/json',
|
||||||
|
@ -211,10 +211,12 @@ export const getOllamaVersion = async (token: string, urlIdx?: number) => {
|
|||||||
return res?.version ?? false;
|
return res?.version ?? false;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getOllamaModels = async (token: string = '') => {
|
export const getOllamaModels = async (token: string = '', urlIdx: null|number = null) => {
|
||||||
let error = null;
|
let error = null;
|
||||||
|
|
||||||
const res = await fetch(`${OLLAMA_API_BASE_URL}/api/tags`, {
|
const res = await fetch(`${OLLAMA_API_BASE_URL}/api/tags${
|
||||||
|
urlIdx !== null ? `/${urlIdx}` : ''
|
||||||
|
}`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
Accept: 'application/json',
|
Accept: 'application/json',
|
||||||
|
@ -4,7 +4,7 @@ import { getUserPosition } from '$lib/utils';
|
|||||||
export const getUserPermissions = async (token: string) => {
|
export const getUserPermissions = async (token: string) => {
|
||||||
let error = null;
|
let error = null;
|
||||||
|
|
||||||
const res = await fetch(`${WEBUI_API_BASE_URL}/users/permissions/user`, {
|
const res = await fetch(`${WEBUI_API_BASE_URL}/users/permissions`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@ -31,7 +31,7 @@ export const getUserPermissions = async (token: string) => {
|
|||||||
export const updateUserPermissions = async (token: string, permissions: object) => {
|
export const updateUserPermissions = async (token: string, permissions: object) => {
|
||||||
let error = null;
|
let error = null;
|
||||||
|
|
||||||
const res = await fetch(`${WEBUI_API_BASE_URL}/users/permissions/user`, {
|
const res = await fetch(`${WEBUI_API_BASE_URL}/users/permissions`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
@ -302,6 +302,7 @@
|
|||||||
<OllamaConnection
|
<OllamaConnection
|
||||||
bind:url
|
bind:url
|
||||||
bind:config={OLLAMA_API_CONFIGS[url]}
|
bind:config={OLLAMA_API_CONFIGS[url]}
|
||||||
|
{idx}
|
||||||
onSubmit={() => {
|
onSubmit={() => {
|
||||||
updateOllamaHandler();
|
updateOllamaHandler();
|
||||||
}}
|
}}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -4,15 +4,20 @@
|
|||||||
|
|
||||||
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||||
import SensitiveInput from '$lib/components/common/SensitiveInput.svelte';
|
import SensitiveInput from '$lib/components/common/SensitiveInput.svelte';
|
||||||
import Cog6 from '$lib/components/icons/Cog6.svelte';
|
|
||||||
import AddConnectionModal from './AddConnectionModal.svelte';
|
import AddConnectionModal from './AddConnectionModal.svelte';
|
||||||
|
|
||||||
|
import Cog6 from '$lib/components/icons/Cog6.svelte';
|
||||||
|
import Wrench from '$lib/components/icons/Wrench.svelte';
|
||||||
|
import ManageOllamaModal from './ManageOllamaModal.svelte';
|
||||||
|
|
||||||
export let onDelete = () => {};
|
export let onDelete = () => {};
|
||||||
export let onSubmit = () => {};
|
export let onSubmit = () => {};
|
||||||
|
|
||||||
export let url = '';
|
export let url = '';
|
||||||
|
export let idx = 0;
|
||||||
export let config = {};
|
export let config = {};
|
||||||
|
|
||||||
|
let showManageModal = false;
|
||||||
let showConfigModal = false;
|
let showConfigModal = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -33,6 +38,8 @@
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<ManageOllamaModal bind:show={showManageModal} urlIdx={idx} />
|
||||||
|
|
||||||
<div class="flex gap-1.5">
|
<div class="flex gap-1.5">
|
||||||
<Tooltip
|
<Tooltip
|
||||||
className="w-full relative"
|
className="w-full relative"
|
||||||
@ -55,6 +62,18 @@
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<div class="flex gap-1">
|
<div class="flex gap-1">
|
||||||
|
<Tooltip content={$i18n.t('Manage')} className="self-start">
|
||||||
|
<button
|
||||||
|
class="self-center p-1 bg-transparent hover:bg-gray-100 dark:bg-gray-900 dark:hover:bg-gray-850 rounded-lg transition"
|
||||||
|
on:click={() => {
|
||||||
|
showManageModal = true;
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<Wrench />
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
<Tooltip content={$i18n.t('Configure')} className="self-start">
|
<Tooltip content={$i18n.t('Configure')} className="self-start">
|
||||||
<button
|
<button
|
||||||
class="self-center p-1 bg-transparent hover:bg-gray-100 dark:bg-gray-900 dark:hover:bg-gray-850 rounded-lg transition"
|
class="self-center p-1 bg-transparent hover:bg-gray-100 dark:bg-gray-900 dark:hover:bg-gray-850 rounded-lg transition"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -23,6 +23,7 @@
|
|||||||
import GroupItem from './Groups/GroupItem.svelte';
|
import GroupItem from './Groups/GroupItem.svelte';
|
||||||
import AddGroupModal from './Groups/AddGroupModal.svelte';
|
import AddGroupModal from './Groups/AddGroupModal.svelte';
|
||||||
import { createNewGroup, getGroups } from '$lib/apis/groups';
|
import { createNewGroup, getGroups } from '$lib/apis/groups';
|
||||||
|
import { getUserPermissions, updateUserPermissions } from '$lib/apis/users';
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
@ -44,6 +45,19 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
let search = '';
|
let search = '';
|
||||||
|
let defaultPermissions = {
|
||||||
|
workspace: {
|
||||||
|
models: false,
|
||||||
|
knowledge: false,
|
||||||
|
prompts: false,
|
||||||
|
tools: false
|
||||||
|
},
|
||||||
|
chat: {
|
||||||
|
delete: true,
|
||||||
|
edit: true,
|
||||||
|
temporary: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let showCreateGroupModal = false;
|
let showCreateGroupModal = false;
|
||||||
let showDefaultPermissionsModal = false;
|
let showDefaultPermissionsModal = false;
|
||||||
@ -64,8 +78,20 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateDefaultPermissionsHandler = async (permissions) => {
|
const updateDefaultPermissionsHandler = async (group) => {
|
||||||
console.log(permissions);
|
console.log(group.permissions);
|
||||||
|
|
||||||
|
const res = await updateUserPermissions(localStorage.token, group.permissions).catch(
|
||||||
|
(error) => {
|
||||||
|
toast.error(error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
toast.success($i18n.t('Default permissions updated successfully'));
|
||||||
|
defaultPermissions = group.permissions;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
@ -73,6 +99,7 @@
|
|||||||
await goto('/');
|
await goto('/');
|
||||||
} else {
|
} else {
|
||||||
await setGroups();
|
await setGroups();
|
||||||
|
defaultPermissions = await getUserPermissions(localStorage.token);
|
||||||
}
|
}
|
||||||
loaded = true;
|
loaded = true;
|
||||||
});
|
});
|
||||||
@ -176,6 +203,7 @@
|
|||||||
<GroupModal
|
<GroupModal
|
||||||
bind:show={showDefaultPermissionsModal}
|
bind:show={showDefaultPermissionsModal}
|
||||||
tabs={['permissions']}
|
tabs={['permissions']}
|
||||||
|
permissions={defaultPermissions}
|
||||||
custom={false}
|
custom={false}
|
||||||
onSubmit={updateDefaultPermissionsHandler}
|
onSubmit={updateDefaultPermissionsHandler}
|
||||||
/>
|
/>
|
||||||
|
@ -26,10 +26,10 @@
|
|||||||
let selectedTab = 'general';
|
let selectedTab = 'general';
|
||||||
let loading = false;
|
let loading = false;
|
||||||
|
|
||||||
let name = '';
|
export let name = '';
|
||||||
let description = '';
|
export let description = '';
|
||||||
|
|
||||||
let permissions = {
|
export let permissions = {
|
||||||
workspace: {
|
workspace: {
|
||||||
models: false,
|
models: false,
|
||||||
knowledge: false,
|
knowledge: false,
|
||||||
@ -42,7 +42,7 @@
|
|||||||
temporary: true
|
temporary: true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let userIds = [];
|
export let userIds = [];
|
||||||
|
|
||||||
const submitHandler = async () => {
|
const submitHandler = async () => {
|
||||||
loading = true;
|
loading = true;
|
||||||
@ -60,7 +60,24 @@
|
|||||||
show = false;
|
show = false;
|
||||||
|
|
||||||
name = '';
|
name = '';
|
||||||
permissions = {};
|
permissions = {
|
||||||
|
model: {
|
||||||
|
filter: false,
|
||||||
|
model_ids: [],
|
||||||
|
default_id: ''
|
||||||
|
},
|
||||||
|
workspace: {
|
||||||
|
models: false,
|
||||||
|
knowledge: false,
|
||||||
|
prompts: false,
|
||||||
|
tools: false
|
||||||
|
},
|
||||||
|
chat: {
|
||||||
|
delete: true,
|
||||||
|
edit: true,
|
||||||
|
temporary: true
|
||||||
|
}
|
||||||
|
};
|
||||||
userIds = [];
|
userIds = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,11 +28,11 @@
|
|||||||
<div class="flex justify-between items-center text-xs pr-2">
|
<div class="flex justify-between items-center text-xs pr-2">
|
||||||
<div class=" text-xs font-medium">{$i18n.t('Model Filtering')}</div>
|
<div class=" text-xs font-medium">{$i18n.t('Model Filtering')}</div>
|
||||||
|
|
||||||
<Switch bind:state={filterEnabled} />
|
<Switch bind:state={permissions.model.filter} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if filterEnabled}
|
{#if permissions.model.filter}
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<div class=" space-y-1.5">
|
<div class=" space-y-1.5">
|
||||||
<div class="flex flex-col w-full">
|
<div class="flex flex-col w-full">
|
||||||
@ -40,9 +40,9 @@
|
|||||||
<div class="text-xs text-gray-500">{$i18n.t('Model IDs')}</div>
|
<div class="text-xs text-gray-500">{$i18n.t('Model IDs')}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if filterModelIds.length > 0}
|
{#if model_ids.length > 0}
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
{#each filterModelIds as modelId, modelIdx}
|
{#each model_ids as modelId, modelIdx}
|
||||||
<div class=" flex gap-2 w-full justify-between items-center">
|
<div class=" flex gap-2 w-full justify-between items-center">
|
||||||
<div class=" text-sm flex-1 rounded-lg">
|
<div class=" text-sm flex-1 rounded-lg">
|
||||||
{modelId}
|
{modelId}
|
||||||
@ -51,7 +51,7 @@
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
filterModelIds = filterModelIds.filter((_, idx) => idx !== modelIdx);
|
model_ids = model_ids.filter((_, idx) => idx !== modelIdx);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Minus strokeWidth="2" className="size-3.5" />
|
<Minus strokeWidth="2" className="size-3.5" />
|
||||||
@ -86,8 +86,8 @@
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
if (selectedModelId && !filterModelIds.includes(selectedModelId)) {
|
if (selectedModelId && !permissions.model.model_ids.includes(selectedModelId)) {
|
||||||
filterModelIds = [...filterModelIds, selectedModelId];
|
permissions.model.model_ids = [...permissions.model.model_ids, selectedModelId];
|
||||||
selectedModelId = '';
|
selectedModelId = '';
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@ -109,11 +109,11 @@
|
|||||||
<div class="flex-1 mr-2">
|
<div class="flex-1 mr-2">
|
||||||
<select
|
<select
|
||||||
class="w-full bg-transparent outline-none py-0.5 text-sm"
|
class="w-full bg-transparent outline-none py-0.5 text-sm"
|
||||||
bind:value={defaultModelId}
|
bind:value={permissions.model.default_id}
|
||||||
placeholder="Select a model"
|
placeholder="Select a model"
|
||||||
>
|
>
|
||||||
<option value="" disabled selected>{$i18n.t('Select a model')}</option>
|
<option value="" disabled selected>{$i18n.t('Select a model')}</option>
|
||||||
{#each filterEnabled ? $models.filter( (model) => filterModelIds.includes(model.id) ) : $models.filter((model) => model.id) as model}
|
{#each permissions.model.filter ? $models.filter( (model) => filterModelIds.includes(model.id) ) : $models.filter((model) => model.id) as model}
|
||||||
<option value={model.id} class="bg-gray-100 dark:bg-gray-700">{model.name}</option>
|
<option value={model.id} class="bg-gray-100 dark:bg-gray-700">{model.name}</option>
|
||||||
{/each}
|
{/each}
|
||||||
</select>
|
</select>
|
||||||
|
@ -557,7 +557,6 @@
|
|||||||
<InputMenu
|
<InputMenu
|
||||||
bind:webSearchEnabled
|
bind:webSearchEnabled
|
||||||
bind:selectedToolIds
|
bind:selectedToolIds
|
||||||
{availableToolIds}
|
|
||||||
uploadFilesHandler={() => {
|
uploadFilesHandler={() => {
|
||||||
filesInputElement.click();
|
filesInputElement.click();
|
||||||
}}
|
}}
|
||||||
|
@ -42,13 +42,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
tools = $_tools.reduce((a, tool, i, arr) => {
|
tools = $_tools.reduce((a, tool, i, arr) => {
|
||||||
if (availableToolIds.includes(tool.id) || ($user?.role ?? 'user') === 'admin') {
|
a[tool.id] = {
|
||||||
a[tool.id] = {
|
name: tool.name,
|
||||||
name: tool.name,
|
description: tool.meta.description,
|
||||||
description: tool.meta.description,
|
enabled: selectedToolIds.includes(tool.id)
|
||||||
enabled: selectedToolIds.includes(tool.id)
|
};
|
||||||
};
|
|
||||||
}
|
|
||||||
return a;
|
return a;
|
||||||
}, {});
|
}, {});
|
||||||
};
|
};
|
||||||
|
20
src/lib/components/icons/Wrench.svelte
Normal file
20
src/lib/components/icons/Wrench.svelte
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let className = 'w-4 h-4';
|
||||||
|
export let strokeWidth = '1.5';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width={strokeWidth}
|
||||||
|
stroke="currentColor"
|
||||||
|
class={className}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M21.75 6.75a4.5 4.5 0 0 1-4.884 4.484c-1.076-.091-2.264.071-2.95.904l-7.152 8.684a2.548 2.548 0 1 1-3.586-3.586l8.684-7.152c.833-.686.995-1.874.904-2.95a4.5 4.5 0 0 1 6.336-4.486l-3.276 3.276a3.004 3.004 0 0 0 2.25 2.25l3.276-3.276c.256.565.398 1.192.398 1.852Z"
|
||||||
|
/>
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M4.867 19.125h.008v.008h-.008v-.008Z" />
|
||||||
|
</svg>
|
@ -112,7 +112,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="my-3 mb-5 grid md:grid-cols-2 lg:grid-cols-3 gap-2">
|
<div class="my-3 mb-5 grid lg:grid-cols-2 xl:grid-cols-3 gap-2">
|
||||||
{#each filteredItems as item}
|
{#each filteredItems as item}
|
||||||
<button
|
<button
|
||||||
class=" flex space-x-4 cursor-pointer text-left w-full px-4 py-3 border border-gray-50 dark:border-gray-850 dark:hover:border-gray-800 hover:bg-gray-50 dark:hover:bg-gray-850 transition rounded-xl"
|
class=" flex space-x-4 cursor-pointer text-left w-full px-4 py-3 border border-gray-50 dark:border-gray-850 dark:hover:border-gray-800 hover:bg-gray-50 dark:hover:bg-gray-850 transition rounded-xl"
|
||||||
|
@ -12,7 +12,12 @@
|
|||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
import { WEBUI_NAME, config, mobile, models as _models, settings, user } from '$lib/stores';
|
import { WEBUI_NAME, config, mobile, models as _models, settings, user } from '$lib/stores';
|
||||||
import { addNewModel, deleteModelById, getModelInfos, updateModelById } from '$lib/apis/models';
|
import {
|
||||||
|
createNewModel,
|
||||||
|
deleteModelById,
|
||||||
|
getWorkspaceModels,
|
||||||
|
updateModelById
|
||||||
|
} from '$lib/apis/models';
|
||||||
|
|
||||||
import { getModels } from '$lib/apis';
|
import { getModels } from '$lib/apis';
|
||||||
|
|
||||||
@ -38,29 +43,15 @@
|
|||||||
let showModelDeleteConfirm = false;
|
let showModelDeleteConfirm = false;
|
||||||
|
|
||||||
$: if (models) {
|
$: if (models) {
|
||||||
filteredModels = models
|
filteredModels = models.filter(
|
||||||
.filter((m) => m?.owned_by !== 'arena')
|
(m) => searchValue === '' || m.name.toLowerCase().includes(searchValue.toLowerCase())
|
||||||
.filter(
|
);
|
||||||
(m) => searchValue === '' || m.name.toLowerCase().includes(searchValue.toLowerCase())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let sortable = null;
|
|
||||||
let searchValue = '';
|
let searchValue = '';
|
||||||
|
|
||||||
const deleteModelHandler = async (model) => {
|
const deleteModelHandler = async (model) => {
|
||||||
console.log(model.info);
|
|
||||||
if (!model?.info) {
|
|
||||||
toast.error(
|
|
||||||
$i18n.t('{{ owner }}: You cannot delete a base model', {
|
|
||||||
owner: model.owned_by.toUpperCase()
|
|
||||||
})
|
|
||||||
);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await deleteModelById(localStorage.token, model.id);
|
const res = await deleteModelById(localStorage.token, model.id);
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
toast.success($i18n.t(`Deleted {{name}}`, { name: model.id }));
|
toast.success($i18n.t(`Deleted {{name}}`, { name: model.id }));
|
||||||
}
|
}
|
||||||
@ -70,17 +61,12 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const cloneModelHandler = async (model) => {
|
const cloneModelHandler = async (model) => {
|
||||||
if ((model?.info?.base_model_id ?? null) === null) {
|
sessionStorage.model = JSON.stringify({
|
||||||
toast.error($i18n.t('You cannot clone a base model'));
|
...model,
|
||||||
return;
|
id: `${model.id}-clone`,
|
||||||
} else {
|
name: `${model.name} (Clone)`
|
||||||
sessionStorage.model = JSON.stringify({
|
});
|
||||||
...model,
|
goto('/workspace/models/create');
|
||||||
id: `${model.id}-clone`,
|
|
||||||
name: `${model.name} (Clone)`
|
|
||||||
});
|
|
||||||
goto('/workspace/models/create');
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const shareModelHandler = async (model) => {
|
const shareModelHandler = async (model) => {
|
||||||
@ -104,58 +90,6 @@
|
|||||||
window.addEventListener('message', messageHandler, false);
|
window.addEventListener('message', messageHandler, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const moveToTopHandler = async (model) => {
|
|
||||||
// find models with position 0 and set them to 1
|
|
||||||
const topModels = models.filter((m) => m.info?.meta?.position === 0);
|
|
||||||
for (const m of topModels) {
|
|
||||||
let info = m.info;
|
|
||||||
if (!info) {
|
|
||||||
info = {
|
|
||||||
id: m.id,
|
|
||||||
name: m.name,
|
|
||||||
meta: {
|
|
||||||
position: 1
|
|
||||||
},
|
|
||||||
params: {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
info.meta = {
|
|
||||||
...info.meta,
|
|
||||||
position: 1
|
|
||||||
};
|
|
||||||
|
|
||||||
await updateModelById(localStorage.token, info.id, info);
|
|
||||||
}
|
|
||||||
|
|
||||||
let info = model.info;
|
|
||||||
|
|
||||||
if (!info) {
|
|
||||||
info = {
|
|
||||||
id: model.id,
|
|
||||||
name: model.name,
|
|
||||||
meta: {
|
|
||||||
position: 0
|
|
||||||
},
|
|
||||||
params: {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
info.meta = {
|
|
||||||
...info.meta,
|
|
||||||
position: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
const res = await updateModelById(localStorage.token, info.id, info);
|
|
||||||
|
|
||||||
if (res) {
|
|
||||||
toast.success($i18n.t(`Model {{name}} is now at the top`, { name: info.id }));
|
|
||||||
}
|
|
||||||
|
|
||||||
await _models.set(await getModels(localStorage.token));
|
|
||||||
models = $_models;
|
|
||||||
};
|
|
||||||
|
|
||||||
const hideModelHandler = async (model) => {
|
const hideModelHandler = async (model) => {
|
||||||
let info = model.info;
|
let info = model.info;
|
||||||
|
|
||||||
@ -206,65 +140,8 @@
|
|||||||
saveAs(blob, `${model.id}-${Date.now()}.json`);
|
saveAs(blob, `${model.id}-${Date.now()}.json`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const positionChangeHandler = async () => {
|
|
||||||
// Get the new order of the models
|
|
||||||
const modelIds = Array.from(document.getElementById('model-list').children).map((child) =>
|
|
||||||
child.id.replace('model-item-', '')
|
|
||||||
);
|
|
||||||
|
|
||||||
// Update the position of the models
|
|
||||||
for (const [index, id] of modelIds.entries()) {
|
|
||||||
const model = $_models.find((m) => m.id === id);
|
|
||||||
if (model) {
|
|
||||||
let info = model.info;
|
|
||||||
|
|
||||||
if (!info) {
|
|
||||||
info = {
|
|
||||||
id: model.id,
|
|
||||||
name: model.name,
|
|
||||||
meta: {
|
|
||||||
position: index
|
|
||||||
},
|
|
||||||
params: {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
info.meta = {
|
|
||||||
...info.meta,
|
|
||||||
position: index
|
|
||||||
};
|
|
||||||
await updateModelById(localStorage.token, info.id, info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await tick();
|
|
||||||
await _models.set(await getModels(localStorage.token));
|
|
||||||
};
|
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
if ($user?.role === 'admin') {
|
models = await getWorkspaceModels(localStorage.token);
|
||||||
models = $_models;
|
|
||||||
|
|
||||||
// Legacy code to sync localModelfiles with models
|
|
||||||
localModelfiles = JSON.parse(localStorage.getItem('modelfiles') ?? '[]');
|
|
||||||
|
|
||||||
if (localModelfiles) {
|
|
||||||
console.log(localModelfiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$mobile) {
|
|
||||||
// SortableJS
|
|
||||||
sortable = new Sortable(document.getElementById('model-list'), {
|
|
||||||
animation: 150,
|
|
||||||
onUpdate: async (event) => {
|
|
||||||
console.log(event);
|
|
||||||
positionChangeHandler();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
models = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const onKeyDown = (event) => {
|
const onKeyDown = (event) => {
|
||||||
if (event.key === 'Shift') {
|
if (event.key === 'Shift') {
|
||||||
@ -376,47 +253,35 @@
|
|||||||
>
|
>
|
||||||
<div class=" self-start w-8 pt-0.5">
|
<div class=" self-start w-8 pt-0.5">
|
||||||
<div
|
<div
|
||||||
class=" rounded-full object-cover {(model?.info?.meta?.hidden ?? false)
|
class=" rounded-full object-cover {(model?.meta?.hidden ?? false)
|
||||||
? 'brightness-90 dark:brightness-50'
|
? 'brightness-90 dark:brightness-50'
|
||||||
: ''} "
|
: ''} "
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src={model?.info?.meta?.profile_image_url ?? '/static/favicon.png'}
|
src={model?.meta?.profile_image_url ?? '/static/favicon.png'}
|
||||||
alt="modelfile profile"
|
alt="modelfile profile"
|
||||||
class=" rounded-full w-full h-auto object-cover"
|
class=" rounded-full w-full h-auto object-cover"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div class=" flex-1 self-center {(model?.meta?.hidden ?? false) ? 'text-gray-500' : ''}">
|
||||||
class=" flex-1 self-center {(model?.info?.meta?.hidden ?? false) ? 'text-gray-500' : ''}"
|
|
||||||
>
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content={marked.parse(
|
content={marked.parse(model?.meta?.description ?? model.id)}
|
||||||
model?.ollama?.digest
|
|
||||||
? `${model?.ollama?.digest} *(${model?.ollama?.modified_at})*`
|
|
||||||
: ''
|
|
||||||
)}
|
|
||||||
className=" w-fit"
|
className=" w-fit"
|
||||||
placement="top-start"
|
placement="top-start"
|
||||||
>
|
>
|
||||||
<div class=" font-semibold line-clamp-1">{model.name}</div>
|
<div class=" font-semibold line-clamp-1">{model.name}</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<div class=" text-xs overflow-hidden text-ellipsis line-clamp-1 text-gray-500">
|
<div class=" text-xs overflow-hidden text-ellipsis line-clamp-1 text-gray-500">
|
||||||
{!!model?.info?.meta?.description
|
{model?.meta?.description ?? model.id}
|
||||||
? model?.info?.meta?.description
|
|
||||||
: model?.ollama?.digest
|
|
||||||
? `${model.id} (${model?.ollama?.digest})`
|
|
||||||
: model.id}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<div class="flex flex-row gap-0.5 self-center">
|
<div class="flex flex-row gap-0.5 self-center">
|
||||||
{#if $user?.role === 'admin' && shiftKey}
|
{#if $user?.role === 'admin' && shiftKey}
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content={(model?.info?.meta?.hidden ?? false)
|
content={(model?.meta?.hidden ?? false) ? $i18n.t('Show Model') : $i18n.t('Hide Model')}
|
||||||
? $i18n.t('Show Model')
|
|
||||||
: $i18n.t('Hide Model')}
|
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
|
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
|
||||||
@ -425,7 +290,7 @@
|
|||||||
hideModelHandler(model);
|
hideModelHandler(model);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{#if model?.info?.meta?.hidden ?? false}
|
{#if model?.meta?.hidden ?? false}
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
fill="none"
|
fill="none"
|
||||||
@ -511,9 +376,6 @@
|
|||||||
exportHandler={() => {
|
exportHandler={() => {
|
||||||
exportModelHandler(model);
|
exportModelHandler(model);
|
||||||
}}
|
}}
|
||||||
moveToTopHandler={() => {
|
|
||||||
moveToTopHandler(model);
|
|
||||||
}}
|
|
||||||
hideHandler={() => {
|
hideHandler={() => {
|
||||||
hideModelHandler(model);
|
hideModelHandler(model);
|
||||||
}}
|
}}
|
||||||
@ -561,7 +423,7 @@
|
|||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await addNewModel(localStorage.token, model.info).catch((error) => {
|
await createNewModel(localStorage.token, model.info).catch((error) => {
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
import { getTools } from '$lib/apis/tools';
|
import { getTools } from '$lib/apis/tools';
|
||||||
import { getFunctions } from '$lib/apis/functions';
|
import { getFunctions } from '$lib/apis/functions';
|
||||||
import { getKnowledgeItems } from '$lib/apis/knowledge';
|
import { getKnowledgeItems } from '$lib/apis/knowledge';
|
||||||
|
import AccessPermissions from '../common/AccessPermissionsModal.svelte';
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
@ -82,7 +83,7 @@
|
|||||||
|
|
||||||
if (baseModel) {
|
if (baseModel) {
|
||||||
if (baseModel.owned_by === 'openai') {
|
if (baseModel.owned_by === 'openai') {
|
||||||
capabilities.usage = baseModel.info?.meta?.capabilities?.usage ?? false;
|
capabilities.usage = basemodel?.meta?.capabilities?.usage ?? false;
|
||||||
} else {
|
} else {
|
||||||
delete capabilities.usage;
|
delete capabilities.usage;
|
||||||
}
|
}
|
||||||
@ -159,33 +160,31 @@
|
|||||||
|
|
||||||
id = model.id;
|
id = model.id;
|
||||||
|
|
||||||
if (model.info.base_model_id) {
|
if (model.base_model_id) {
|
||||||
const base_model = $models
|
const base_model = $models
|
||||||
.filter((m) => !m?.preset && m?.owned_by !== 'arena')
|
.filter((m) => !m?.preset && m?.owned_by !== 'arena')
|
||||||
.find((m) =>
|
.find((m) => [model.base_model_id, `${model.base_model_id}:latest`].includes(m.id));
|
||||||
[model.info.base_model_id, `${model.info.base_model_id}:latest`].includes(m.id)
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log('base_model', base_model);
|
console.log('base_model', base_model);
|
||||||
|
|
||||||
if (base_model) {
|
if (base_model) {
|
||||||
model.info.base_model_id = base_model.id;
|
model.base_model_id = base_model.id;
|
||||||
} else {
|
} else {
|
||||||
model.info.base_model_id = null;
|
model.base_model_id = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
params = { ...params, ...model?.info?.params };
|
params = { ...params, ...model?.params };
|
||||||
params.stop = params?.stop
|
params.stop = params?.stop
|
||||||
? (typeof params.stop === 'string' ? params.stop.split(',') : (params?.stop ?? [])).join(
|
? (typeof params.stop === 'string' ? params.stop.split(',') : (params?.stop ?? [])).join(
|
||||||
','
|
','
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
toolIds = model?.info?.meta?.toolIds ?? [];
|
toolIds = model?.meta?.toolIds ?? [];
|
||||||
filterIds = model?.info?.meta?.filterIds ?? [];
|
filterIds = model?.meta?.filterIds ?? [];
|
||||||
actionIds = model?.info?.meta?.actionIds ?? [];
|
actionIds = model?.meta?.actionIds ?? [];
|
||||||
knowledge = (model?.info?.meta?.knowledge ?? []).map((item) => {
|
knowledge = (model?.meta?.knowledge ?? []).map((item) => {
|
||||||
if (item?.collection_name) {
|
if (item?.collection_name) {
|
||||||
return {
|
return {
|
||||||
id: item.collection_name,
|
id: item.collection_name,
|
||||||
@ -203,7 +202,7 @@
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
capabilities = { ...capabilities, ...(model?.info?.meta?.capabilities ?? {}) };
|
capabilities = { ...capabilities, ...(model?.meta?.capabilities ?? {}) };
|
||||||
if (model?.owned_by === 'openai') {
|
if (model?.owned_by === 'openai') {
|
||||||
capabilities.usage = false;
|
capabilities.usage = false;
|
||||||
}
|
}
|
||||||
@ -212,8 +211,8 @@
|
|||||||
...info,
|
...info,
|
||||||
...JSON.parse(
|
...JSON.parse(
|
||||||
JSON.stringify(
|
JSON.stringify(
|
||||||
model?.info
|
model
|
||||||
? model?.info
|
? model
|
||||||
: {
|
: {
|
||||||
id: model.id,
|
id: model.id,
|
||||||
name: model.name
|
name: model.name
|
||||||
@ -441,6 +440,26 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="my-1">
|
||||||
|
<div class="">
|
||||||
|
<Tags
|
||||||
|
tags={info?.meta?.tags ?? []}
|
||||||
|
on:delete={(e) => {
|
||||||
|
const tagName = e.detail;
|
||||||
|
info.meta.tags = info.meta.tags.filter((tag) => tag.name !== tagName);
|
||||||
|
}}
|
||||||
|
on:add={(e) => {
|
||||||
|
const tagName = e.detail;
|
||||||
|
if (!(info?.meta?.tags ?? null)) {
|
||||||
|
info.meta.tags = [{ name: tagName }];
|
||||||
|
} else {
|
||||||
|
info.meta.tags = [...info.meta.tags, { name: tagName }];
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<hr class=" dark:border-gray-850 my-1.5" />
|
<hr class=" dark:border-gray-850 my-1.5" />
|
||||||
|
|
||||||
<div class="my-2">
|
<div class="my-2">
|
||||||
@ -620,28 +639,8 @@
|
|||||||
<Capabilities bind:capabilities />
|
<Capabilities bind:capabilities />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="my-1">
|
<div class="my-2">
|
||||||
<div class="flex w-full justify-between items-center">
|
<AccessPermissions />
|
||||||
<div class=" self-center text-sm font-semibold">{$i18n.t('Tags')}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-2">
|
|
||||||
<Tags
|
|
||||||
tags={info?.meta?.tags ?? []}
|
|
||||||
on:delete={(e) => {
|
|
||||||
const tagName = e.detail;
|
|
||||||
info.meta.tags = info.meta.tags.filter((tag) => tag.name !== tagName);
|
|
||||||
}}
|
|
||||||
on:add={(e) => {
|
|
||||||
const tagName = e.detail;
|
|
||||||
if (!(info?.meta?.tags ?? null)) {
|
|
||||||
info.meta.tags = [{ name: tagName }];
|
|
||||||
} else {
|
|
||||||
info.meta.tags = [...info.meta.tags, { name: tagName }];
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="my-2 text-gray-300 dark:text-gray-700">
|
<div class="my-2 text-gray-300 dark:text-gray-700">
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
export let cloneHandler: Function;
|
export let cloneHandler: Function;
|
||||||
export let exportHandler: Function;
|
export let exportHandler: Function;
|
||||||
|
|
||||||
export let moveToTopHandler: Function;
|
|
||||||
export let hideHandler: Function;
|
export let hideHandler: Function;
|
||||||
export let deleteHandler: Function;
|
export let deleteHandler: Function;
|
||||||
export let onClose: Function;
|
export let onClose: Function;
|
||||||
@ -83,71 +82,6 @@
|
|||||||
<div class="flex items-center">{$i18n.t('Export')}</div>
|
<div class="flex items-center">{$i18n.t('Export')}</div>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
|
|
||||||
{#if user?.role === 'admin'}
|
|
||||||
<DropdownMenu.Item
|
|
||||||
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
|
|
||||||
on:click={() => {
|
|
||||||
moveToTopHandler();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ArrowUpCircle />
|
|
||||||
|
|
||||||
<div class="flex items-center">{$i18n.t('Move to Top')}</div>
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
|
|
||||||
<DropdownMenu.Item
|
|
||||||
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
|
|
||||||
on:click={() => {
|
|
||||||
hideHandler();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{#if model?.info?.meta?.hidden ?? false}
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke-width="1.5"
|
|
||||||
stroke="currentColor"
|
|
||||||
class="size-4"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
d="M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.522 10.522 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
{:else}
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke-width="1.5"
|
|
||||||
stroke="currentColor"
|
|
||||||
class="size-4"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<div class="flex items-center">
|
|
||||||
{#if model?.info?.meta?.hidden ?? false}
|
|
||||||
{$i18n.t('Show Model')}
|
|
||||||
{:else}
|
|
||||||
{$i18n.t('Hide Model')}
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<hr class="border-gray-100 dark:border-gray-800 my-1" />
|
<hr class="border-gray-100 dark:border-gray-800 my-1" />
|
||||||
|
|
||||||
<DropdownMenu.Item
|
<DropdownMenu.Item
|
||||||
|
@ -0,0 +1,101 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { getContext } from 'svelte';
|
||||||
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
|
export let type = 'private';
|
||||||
|
|
||||||
|
let query = '';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<div class=" text-sm font-semibold mb-0.5">{$i18n.t('People with access')}</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="flex w-full py-1">
|
||||||
|
<div class="flex flex-1">
|
||||||
|
<div class=" self-center mr-3">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
class="w-4 h-4"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
class=" w-full text-sm pr-4 placeholder:text-gray-300 dark:placeholder:text-gray-700 outline-none bg-transparent"
|
||||||
|
bind:value={query}
|
||||||
|
placeholder={$i18n.t('Add user or groups')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="">
|
||||||
|
<div class=" text-sm font-semibold mb-2">{$i18n.t('General access')}</div>
|
||||||
|
|
||||||
|
<div class="flex gap-2.5 items-center">
|
||||||
|
<div>
|
||||||
|
<div class=" p-2 bg-gray-700 rounded-full">
|
||||||
|
{#if type === 'private'}
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke="currentColor"
|
||||||
|
class="w-5 h-5"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
{:else}
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke="currentColor"
|
||||||
|
class="w-5 h-5"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M6.115 5.19l.319 1.913A6 6 0 008.11 10.36L9.75 12l-.387.775c-.217.433-.132.956.21 1.298l1.348 1.348c.21.21.329.497.329.795v1.089c0 .426.24.815.622 1.006l.153.076c.433.217.956.132 1.298-.21l.723-.723a8.7 8.7 0 002.288-4.042 1.087 1.087 0 00-.358-1.099l-1.33-1.108c-.251-.21-.582-.299-.905-.245l-1.17.195a1.125 1.125 0 01-.98-.314l-.295-.295a1.125 1.125 0 010-1.591l.13-.132a1.125 1.125 0 011.3-.21l.603.302a.809.809 0 001.086-1.086L14.25 7.5l1.256-.837a4.5 4.5 0 001.528-1.732l.146-.292M6.115 5.19A9 9 0 1017.18 4.64M6.115 5.19A8.965 8.965 0 0112 3c1.929 0 3.716.607 5.18 1.64"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<select
|
||||||
|
id="models"
|
||||||
|
class="outline-none bg-transparent text-sm font-medium rounded-lg block w-fit pr-10 max-w-full placeholder-gray-400"
|
||||||
|
bind:value={type}
|
||||||
|
>
|
||||||
|
<option class=" text-gray-700" value="private" selected>Private</option>
|
||||||
|
<option class=" text-gray-700" value="public" selected>Public</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<div class=" text-xs text-gray-400 font-medium">
|
||||||
|
{#if type === 'private'}
|
||||||
|
{$i18n.t('Only users with permission can access')}
|
||||||
|
{:else if type === 'public'}
|
||||||
|
{$i18n.t('Accessible to all users')}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -5,7 +5,7 @@
|
|||||||
import { models } from '$lib/stores';
|
import { models } from '$lib/stores';
|
||||||
|
|
||||||
import { onMount, tick, getContext } from 'svelte';
|
import { onMount, tick, getContext } from 'svelte';
|
||||||
import { addNewModel, getModelById, getModelInfos } from '$lib/apis/models';
|
import { createNewModel, getModelById } from '$lib/apis/models';
|
||||||
import { getModels } from '$lib/apis';
|
import { getModels } from '$lib/apis';
|
||||||
|
|
||||||
import ModelEditor from '$lib/components/workspace/Models/ModelEditor.svelte';
|
import ModelEditor from '$lib/components/workspace/Models/ModelEditor.svelte';
|
||||||
@ -21,7 +21,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (modelInfo) {
|
if (modelInfo) {
|
||||||
const res = await addNewModel(localStorage.token, {
|
const res = await createNewModel(localStorage.token, {
|
||||||
...modelInfo,
|
...modelInfo,
|
||||||
meta: {
|
meta: {
|
||||||
...modelInfo.meta,
|
...modelInfo.meta,
|
||||||
|
@ -8,17 +8,20 @@
|
|||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { models } from '$lib/stores';
|
import { models } from '$lib/stores';
|
||||||
|
|
||||||
import { updateModelById } from '$lib/apis/models';
|
import { getModelById, updateModelById } from '$lib/apis/models';
|
||||||
|
|
||||||
import { getModels } from '$lib/apis';
|
import { getModels } from '$lib/apis';
|
||||||
import ModelEditor from '$lib/components/workspace/Models/ModelEditor.svelte';
|
import ModelEditor from '$lib/components/workspace/Models/ModelEditor.svelte';
|
||||||
|
|
||||||
let model = null;
|
let model = null;
|
||||||
|
|
||||||
onMount(() => {
|
onMount(async () => {
|
||||||
const _id = $page.url.searchParams.get('id');
|
const _id = $page.url.searchParams.get('id');
|
||||||
if (_id) {
|
if (_id) {
|
||||||
model = $models.find((m) => m.id === _id && m?.owned_by !== 'arena');
|
model = await getModelById(localStorage.token, _id).catch((e) => {
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
if (!model) {
|
if (!model) {
|
||||||
goto('/workspace/models');
|
goto('/workspace/models');
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user