This commit is contained in:
Timothy Jaeryang Baek
2026-07-15 17:50:26 -04:00
parent db934a3b4f
commit ba067258de
39 changed files with 1540 additions and 1442 deletions
@@ -3,8 +3,6 @@
import { getContext, onMount } from 'svelte';
const i18n = getContext<any>('i18n');
import { settings } from '$lib/stores';
import Modal from '$lib/components/common/Modal.svelte';
import SensitiveInput from '$lib/components/common/SensitiveInput.svelte';
import XMark from '$lib/components/icons/XMark.svelte';
@@ -61,9 +59,9 @@
let loadingPolicy = false;
let policyLoadError = '';
const highContrastInputClass =
const inputClass =
'rounded-lg border border-gray-100/50 bg-gray-50/40 px-2 py-1.5 text-gray-700 outline-hidden transition-colors placeholder:text-gray-300 focus:border-blue-400 dark:border-white/[0.04] dark:bg-white/[0.03] dark:text-gray-300 dark:placeholder:text-gray-700 dark:focus:border-blue-500';
const highContrastSelectClass =
const selectClass =
'rounded-lg border border-gray-100/50 bg-gray-50/40 px-2 py-1.5 text-gray-700 outline-hidden transition-colors focus:border-blue-400 dark:border-white/[0.04] dark:bg-white/[0.03] dark:text-gray-300 dark:focus:border-blue-500';
const stringifyJson = (value: object | null | undefined) => {
@@ -399,9 +397,7 @@
<div class="flex gap-2">
<div class="flex flex-col flex-1">
<div class="flex justify-between mb-0.5">
<label
for="terminal-name"
class={`text-xs ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
<label for="terminal-name" class={`text-xs text-gray-500`}
>{$i18n.t('Name')}</label
>
</div>
@@ -409,7 +405,7 @@
<div class="flex flex-1 items-center">
<input
id="terminal-name"
class={`w-full flex-1 text-sm ${($settings?.highContrastMode ?? false) ? highContrastInputClass : 'bg-transparent outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700'}`}
class={`w-full flex-1 text-sm ${inputClass}`}
type="text"
bind:value={name}
placeholder={$i18n.t('My Terminal')}
@@ -420,9 +416,7 @@
{#if !direct}
<div class="flex flex-col flex-1">
<div class="flex justify-between mb-0.5">
<label
for="terminal-id"
class={`text-xs ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
<label for="terminal-id" class={`text-xs text-gray-500`}
>{$i18n.t('ID')}
<span class="opacity-50">({$i18n.t('optional')})</span></label
>
@@ -430,7 +424,7 @@
<div class="flex flex-1 items-center">
<input
id="terminal-id"
class={`w-full flex-1 text-sm font-mono ${($settings?.highContrastMode ?? false) ? highContrastInputClass : 'bg-transparent outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700'}`}
class={`w-full flex-1 text-sm font-mono ${inputClass}`}
type="text"
bind:value={id}
placeholder="auto"
@@ -444,17 +438,13 @@
<div class="flex gap-2 mt-2">
<div class="flex flex-col w-full">
<div class="flex justify-between mb-0.5">
<label
for="terminal-url"
class={`text-xs ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
>{$i18n.t('URL')}</label
>
<label for="terminal-url" class={`text-xs text-gray-500`}>{$i18n.t('URL')}</label>
</div>
<div class="flex flex-1 items-center">
<input
id="terminal-url"
class={`w-full flex-1 text-sm ${($settings?.highContrastMode ?? false) ? highContrastInputClass : 'bg-transparent outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700'}`}
class={`w-full flex-1 text-sm ${inputClass}`}
type="text"
bind:value={url}
placeholder="http://localhost:9900"
@@ -519,16 +509,14 @@
<div class="flex gap-2 mt-2">
<div class="flex flex-col w-full">
<div class="flex justify-between mb-0.5">
<div
class={`text-xs ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
>
<div class={`text-xs text-gray-500`}>
{$i18n.t('Policy ID')}
</div>
</div>
<div class="flex flex-1 items-center">
<input
id="policy-id"
class={`w-full flex-1 text-sm font-mono ${($settings?.highContrastMode ?? false) ? highContrastInputClass : 'bg-transparent outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700'}`}
class={`w-full flex-1 text-sm font-mono ${inputClass}`}
type="text"
bind:value={policyId}
placeholder="python-ds"
@@ -549,9 +537,7 @@
<div class="flex gap-2 mt-2">
<div class="flex flex-col w-full">
<div class="flex justify-between mb-0.5">
<div
class={`text-xs ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
>
<div class={`text-xs text-gray-500`}>
{$i18n.t('Image')}
<span class="opacity-50">({$i18n.t('optional')})</span>
</div>
@@ -559,7 +545,7 @@
<div class="flex flex-1 items-center">
<input
id="policy-image"
class={`w-full flex-1 text-sm font-mono ${($settings?.highContrastMode ?? false) ? highContrastInputClass : 'bg-transparent outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700'}`}
class={`w-full flex-1 text-sm font-mono ${inputClass}`}
type="text"
bind:value={policyImage}
placeholder="ghcr.io/open-webui/open-terminal:latest"
@@ -572,16 +558,14 @@
<div class="flex gap-2 mt-2">
<div class="flex flex-col flex-1">
<div class="flex justify-between mb-0.5">
<div
class={`text-xs ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
>
<div class={`text-xs text-gray-500`}>
{$i18n.t('CPU')}
</div>
</div>
<div class="flex flex-1 items-center">
<input
id="policy-cpu"
class={`w-full flex-1 text-sm font-mono ${($settings?.highContrastMode ?? false) ? highContrastInputClass : 'bg-transparent outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700'}`}
class={`w-full flex-1 text-sm font-mono ${inputClass}`}
type="text"
bind:value={policyCpu}
placeholder="1"
@@ -591,16 +575,14 @@
</div>
<div class="flex flex-col flex-1">
<div class="flex justify-between mb-0.5">
<div
class={`text-xs ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
>
<div class={`text-xs text-gray-500`}>
{$i18n.t('Memory')}
</div>
</div>
<div class="flex flex-1 items-center">
<input
id="policy-memory"
class={`w-full flex-1 text-sm font-mono ${($settings?.highContrastMode ?? false) ? highContrastInputClass : 'bg-transparent outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700'}`}
class={`w-full flex-1 text-sm font-mono ${inputClass}`}
type="text"
bind:value={policyMemory}
placeholder="1Gi"
@@ -613,16 +595,14 @@
<div class="flex gap-2 mt-2">
<div class="flex flex-col flex-1">
<div class="flex justify-between mb-0.5">
<div
class={`text-xs ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
>
<div class={`text-xs text-gray-500`}>
{$i18n.t('Storage')}
</div>
</div>
<div class="flex gap-2">
<div class="flex-shrink-0 self-start">
<select
class={`w-full text-sm pr-5 ${($settings?.highContrastMode ?? false) ? highContrastSelectClass : 'bg-transparent outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700 dark:bg-gray-900'}`}
class={`w-full text-sm pr-5 ${selectClass}`}
bind:value={policyStorage}
>
<option value="ephemeral">{$i18n.t('Ephemeral')}</option>
@@ -633,7 +613,7 @@
<div class="flex flex-1 items-center">
<input
id="policy-storage-size"
class={`w-full flex-1 text-sm font-mono ${($settings?.highContrastMode ?? false) ? highContrastInputClass : 'bg-transparent outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700'}`}
class={`w-full flex-1 text-sm font-mono ${inputClass}`}
type="text"
bind:value={policyStorageSize}
placeholder="5Gi"
@@ -646,9 +626,7 @@
<div class="flex flex-col flex-1">
<div class="flex justify-between mb-0.5">
<div
class={`text-xs ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
>
<div class={`text-xs text-gray-500`}>
{$i18n.t('Idle Timeout')}
<span class="opacity-50">({$i18n.t('min')})</span>
</div>
@@ -656,7 +634,7 @@
<div class="flex flex-1 items-center">
<input
id="idle-timeout"
class={`w-full flex-1 text-sm font-mono ${($settings?.highContrastMode ?? false) ? highContrastInputClass : 'bg-transparent outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700'}`}
class={`w-full flex-1 text-sm font-mono ${inputClass}`}
type="number"
min="0"
bind:value={policyIdleTimeout}
@@ -671,9 +649,7 @@
<div class="flex gap-2 mt-2">
<div class="flex flex-col w-full">
<div class="flex justify-between items-center mb-0.5">
<div
class={`text-xs ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
>
<div class={`text-xs text-gray-500`}>
{$i18n.t('Environment Variables')}
</div>
<button
@@ -688,13 +664,13 @@
{#each policyEnvPairs as pair, idx}
<div class="flex gap-1.5 mb-1">
<input
class={`flex-1 text-sm font-mono ${($settings?.highContrastMode ?? false) ? highContrastInputClass : 'bg-transparent outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700'}`}
class={`flex-1 text-sm font-mono ${inputClass}`}
type="text"
bind:value={pair.key}
placeholder="KEY"
/>
<input
class={`flex-[2] text-sm font-mono ${($settings?.highContrastMode ?? false) ? highContrastInputClass : 'bg-transparent outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700'}`}
class={`flex-[2] text-sm font-mono ${inputClass}`}
type="text"
bind:value={pair.value}
placeholder="value"
@@ -715,15 +691,13 @@
<div class="flex gap-2 mt-2">
<div class="flex flex-col w-full">
<div class="flex justify-between mb-0.5">
<div
class={`text-xs ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
>
<div class={`text-xs text-gray-500`}>
{$i18n.t('Lifecycle JSON')}
</div>
</div>
<textarea
id="lifecycle-json"
class={`w-full min-h-24 resize-y text-xs font-mono ${($settings?.highContrastMode ?? false) ? highContrastInputClass : 'rounded-lg border border-gray-200 bg-transparent p-2 outline-hidden placeholder:text-gray-300 dark:border-gray-800 dark:placeholder:text-gray-700'}`}
class={`w-full min-h-24 resize-y text-xs font-mono ${inputClass}`}
bind:value={lifecycleJson}
spellcheck="false"
placeholder={`{\n "reset": {\n "schedule": "@weekly",\n "timezone": "UTC"\n }\n}`}
@@ -794,9 +768,7 @@
<div class="flex flex-col w-full">
<div class="flex justify-between items-center mb-0.5">
<div class="flex gap-2 items-center">
<div
class={`text-xs ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
>
<div class={`text-xs text-gray-500`}>
{$i18n.t('OpenAPI Spec')}
</div>
</div>
@@ -809,7 +781,7 @@
>{$i18n.t('openapi.json URL or Path')}</label
>
<input
class={`w-full text-sm ${($settings?.highContrastMode ?? false) ? highContrastInputClass : 'bg-transparent outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700'}`}
class={`w-full text-sm ${inputClass}`}
type="text"
id="openapi-path"
bind:value={path}
@@ -821,9 +793,7 @@
</div>
</div>
<div
class={`text-xs mt-1 ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
>
<div class={`text-xs mt-1 text-gray-500`}>
{$i18n.t(`WebUI will make requests to "{{url}}"`, {
url: path.includes('://')
? path
@@ -838,9 +808,7 @@
<div class="flex flex-col w-full">
<div class="flex justify-between items-center">
<div class="flex gap-2 items-center">
<div
class={`text-xs ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
>
<div class={`text-xs text-gray-500`}>
{$i18n.t('Auth')}
</div>
</div>
@@ -848,10 +816,7 @@
<div class="flex gap-2">
<div class="flex-shrink-0 self-start">
<select
class={`w-full text-sm pr-5 ${($settings?.highContrastMode ?? false) ? highContrastSelectClass : 'bg-transparent outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700 dark:bg-gray-900'}`}
bind:value={auth_type}
>
<select class={`w-full text-sm pr-5 ${selectClass}`} bind:value={auth_type}>
<option value="none">{$i18n.t('None')}</option>
<option value="bearer">{$i18n.t('Bearer')}</option>
{#if !direct}
@@ -869,21 +834,15 @@
required={false}
/>
{:else if auth_type === 'none'}
<div
class={`text-xs self-center translate-y-[1px] ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
>
<div class={`text-xs self-center translate-y-[1px] text-gray-500`}>
{$i18n.t('No authentication')}
</div>
{:else if auth_type === 'session'}
<div
class={`text-xs self-center translate-y-[1px] ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
>
<div class={`text-xs self-center translate-y-[1px] text-gray-500`}>
{$i18n.t('Forwards system user session credentials to authenticate')}
</div>
{:else if auth_type === 'system_oauth'}
<div
class={`text-xs self-center translate-y-[1px] ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
>
<div class={`text-xs self-center translate-y-[1px] text-gray-500`}>
{$i18n.t('Forwards system user OAuth access token to authenticate')}
</div>
{/if}