feat: open terminal integration
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { createEventDispatcher, onMount, getContext, tick } from 'svelte';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { getModels as _getModels } from '$lib/apis';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
@@ -12,16 +13,34 @@
|
||||
import Spinner from '$lib/components/common/Spinner.svelte';
|
||||
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||
import Plus from '$lib/components/icons/Plus.svelte';
|
||||
import Cog6 from '$lib/components/icons/Cog6.svelte';
|
||||
import Cloud from '$lib/components/icons/Cloud.svelte';
|
||||
import Connection from '$lib/components/chat/Settings/Tools/Connection.svelte';
|
||||
import SensitiveInput from '$lib/components/common/SensitiveInput.svelte';
|
||||
|
||||
import AddToolServerModal from '$lib/components/AddToolServerModal.svelte';
|
||||
import { getToolServerConnections, setToolServerConnections } from '$lib/apis/configs';
|
||||
import AddTerminalServerModal from '$lib/components/AddTerminalServerModal.svelte';
|
||||
import ConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
|
||||
|
||||
import {
|
||||
getToolServerConnections,
|
||||
setToolServerConnections,
|
||||
getTerminalServerConnections,
|
||||
setTerminalServerConnections
|
||||
} from '$lib/apis/configs';
|
||||
|
||||
export let saveSettings: Function;
|
||||
|
||||
let servers = null;
|
||||
let showConnectionModal = false;
|
||||
|
||||
// Terminal server admin connections
|
||||
let terminalConnections: { id: string; url: string; key: string; name: string }[] = [];
|
||||
let showAddTerminalModal = false;
|
||||
let editTerminalIdx: number | null = null;
|
||||
let showDeleteTerminalConfirm = false;
|
||||
let deleteTerminalIdx: number | null = null;
|
||||
|
||||
const addConnectionHandler = async (server) => {
|
||||
servers = [...servers, server];
|
||||
await updateHandler();
|
||||
@@ -32,7 +51,6 @@
|
||||
TOOL_SERVER_CONNECTIONS: servers
|
||||
}).catch((err) => {
|
||||
toast.error($i18n.t('Failed to save connections'));
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
@@ -41,14 +59,92 @@
|
||||
}
|
||||
};
|
||||
|
||||
const saveTerminalServers = async () => {
|
||||
const res = await setTerminalServerConnections(localStorage.token, {
|
||||
TERMINAL_SERVER_CONNECTIONS: terminalConnections
|
||||
}).catch((err) => {
|
||||
toast.error($i18n.t('Failed to save terminal servers'));
|
||||
return null;
|
||||
});
|
||||
|
||||
if (res) {
|
||||
toast.success($i18n.t('Terminal servers saved'));
|
||||
}
|
||||
};
|
||||
|
||||
const addTerminalConnection = (server: { url: string; key: string; name?: string }) => {
|
||||
terminalConnections = [
|
||||
...terminalConnections,
|
||||
{ id: uuidv4(), url: server.url, key: server.key, name: server.name ?? '' }
|
||||
];
|
||||
saveTerminalServers();
|
||||
};
|
||||
|
||||
const updateTerminalConnection = (
|
||||
idx: number,
|
||||
updated: { url: string; key: string; name?: string }
|
||||
) => {
|
||||
terminalConnections = terminalConnections.map((c, i) =>
|
||||
i === idx ? { ...c, url: updated.url, key: updated.key, name: updated.name ?? '' } : c
|
||||
);
|
||||
saveTerminalServers();
|
||||
};
|
||||
|
||||
const removeTerminalConnection = (idx: number) => {
|
||||
terminalConnections = terminalConnections.filter((_, i) => i !== idx);
|
||||
saveTerminalServers();
|
||||
};
|
||||
|
||||
onMount(async () => {
|
||||
const res = await getToolServerConnections(localStorage.token);
|
||||
servers = res.TOOL_SERVER_CONNECTIONS;
|
||||
|
||||
// Load terminal server connections
|
||||
try {
|
||||
const terminalRes = await getTerminalServerConnections(localStorage.token);
|
||||
if (terminalRes?.TERMINAL_SERVER_CONNECTIONS) {
|
||||
terminalConnections = terminalRes.TERMINAL_SERVER_CONNECTIONS;
|
||||
}
|
||||
} catch {
|
||||
// Not configured yet
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<AddToolServerModal bind:show={showConnectionModal} onSubmit={addConnectionHandler} />
|
||||
|
||||
<AddTerminalServerModal
|
||||
admin
|
||||
bind:show={showAddTerminalModal}
|
||||
edit={editTerminalIdx !== null}
|
||||
connection={editTerminalIdx !== null ? terminalConnections[editTerminalIdx] : null}
|
||||
onSubmit={(c) => {
|
||||
if (editTerminalIdx !== null) {
|
||||
updateTerminalConnection(editTerminalIdx, c);
|
||||
editTerminalIdx = null;
|
||||
} else {
|
||||
addTerminalConnection(c);
|
||||
}
|
||||
}}
|
||||
onDelete={() => {
|
||||
if (editTerminalIdx !== null) {
|
||||
deleteTerminalIdx = editTerminalIdx;
|
||||
showDeleteTerminalConfirm = true;
|
||||
editTerminalIdx = null;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<ConfirmDialog
|
||||
bind:show={showDeleteTerminalConfirm}
|
||||
on:confirm={() => {
|
||||
if (deleteTerminalIdx !== null) {
|
||||
removeTerminalConnection(deleteTerminalIdx);
|
||||
deleteTerminalIdx = null;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<form
|
||||
class="flex flex-col h-full justify-between text-sm"
|
||||
on:submit|preventDefault={() => {
|
||||
@@ -64,9 +160,6 @@
|
||||
<hr class=" border-gray-100/30 dark:border-gray-850/30 my-2" />
|
||||
|
||||
<div class="mb-2.5 flex flex-col w-full justify-between">
|
||||
<!-- {$i18n.t(`Failed to connect to {{URL}} OpenAPI tool server`, {
|
||||
URL: 'server?.url'
|
||||
})} -->
|
||||
<div class="flex justify-between items-center mb-0.5">
|
||||
<div class="font-medium">{$i18n.t('Manage Tool Servers')}</div>
|
||||
|
||||
@@ -98,9 +191,98 @@
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<div class="my-1.5">
|
||||
{#if servers.length === 0}
|
||||
<div class="text-xs text-gray-400 dark:text-gray-500">
|
||||
{$i18n.t('No tool server connections configured.')}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="my-1.5">
|
||||
<div class="text-xs text-gray-500">
|
||||
{$i18n.t('Connect to your own OpenAPI compatible external tool servers.')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class=" border-gray-100/30 dark:border-gray-850/30 my-4" />
|
||||
|
||||
<div class="mb-2.5 flex flex-col w-full">
|
||||
<div class="flex justify-between items-center mb-1">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="font-medium">{$i18n.t('Open Terminal')}</div>
|
||||
<span
|
||||
class="text-[0.65rem] font-medium uppercase px-1.5 py-0.5 rounded-full bg-gray-100 dark:bg-gray-800 text-gray-500 dark:text-gray-400"
|
||||
>{$i18n.t('Experimental')}</span
|
||||
>
|
||||
</div>
|
||||
|
||||
<Tooltip content={$i18n.t('Add Connection')}>
|
||||
<button
|
||||
class="px-1"
|
||||
on:click={() => {
|
||||
editTerminalIdx = null;
|
||||
showAddTerminalModal = true;
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
<Plus />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-1.5">
|
||||
{#each terminalConnections as connection, idx}
|
||||
<div class="flex w-full gap-2 items-center">
|
||||
<Tooltip className="w-full relative" content={''} placement="top-start">
|
||||
<div class="flex w-full">
|
||||
<div class="flex-1 relative flex gap-1.5 items-center">
|
||||
<Tooltip content={$i18n.t('Terminal')}>
|
||||
<Cloud className="size-4" strokeWidth="1.5" />
|
||||
</Tooltip>
|
||||
|
||||
<div class="capitalize outline-hidden w-full bg-transparent text-sm">
|
||||
{connection.name || connection.url || $i18n.t('New Terminal')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
||||
<div class="flex gap-1 items-center">
|
||||
<Tooltip content={$i18n.t('Configure')}>
|
||||
<button
|
||||
class="self-center p-1 bg-transparent hover:bg-gray-100 dark:hover:bg-gray-850 rounded-lg transition"
|
||||
on:click={() => {
|
||||
editTerminalIdx = idx;
|
||||
showAddTerminalModal = true;
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
<Cog6 />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
{#if terminalConnections.length === 0}
|
||||
<div class="text-xs text-gray-400 dark:text-gray-500">
|
||||
{$i18n.t('No terminal connections configured.')}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="mt-1.5">
|
||||
<div class="text-xs text-gray-500">
|
||||
{$i18n.t('Connect to your own OpenAPI compatible external tool servers.')}
|
||||
{$i18n.t(
|
||||
'Connect to Open Terminal instances. All users will have access to file browsing and terminal tools through these servers.'
|
||||
)}
|
||||
</div>
|
||||
<div class="text-xs text-gray-600 dark:text-gray-300 mt-1">
|
||||
<a
|
||||
class="underline"
|
||||
href="https://github.com/open-webui/open-terminal"
|
||||
target="_blank">{$i18n.t('Learn more about Open Terminal')} ↗</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user