This commit is contained in:
Timothy Jaeryang Baek committed 2026-07-17 05:09:29 -04:00
1 parent 3316ba76aa
commit 5424ac5891
4 files changed
+130 -87

No files matched your search

@@ -18,36 +18,49 @@
export let actions: Action[] = [];
export let selectedActionIds: string[] = [];
$: selectableActions = actions.filter((action) => !action.is_global);
$: selectedActions = actions.filter(
(action) => action.is_global || selectedActionIds.includes(action.id)
);
$: availableActions = actions.filter(
(action) => !action.is_global && !selectedActionIds.includes(action.id)
);
const selectAction = (action: Action) => {
selectedActionIds = [...selectedActionIds, action.id];
const toggleAction = (action: Action) => {
selectedActionIds = selectedActionIds.includes(action.id)
? selectedActionIds.filter((id) => id !== action.id)
: [...selectedActionIds, action.id];
};
</script>
{#if actions.length > 0}
<div>
<div class="flex w-full justify-between mb-1">
<div class="flex w-full items-center gap-2 mb-1">
<div class=" self-center text-xs text-gray-500">{$i18n.t('Actions')}</div>
{#if selectableActions.length > 0}
<TypeaheadSelector
id="model-actions-selector"
items={selectableActions.map((action) => ({
...action,
description: action.meta?.description
}))}
selectedIds={selectedActionIds}
placeholder={$i18n.t('Search actions')}
triggerLabel={$i18n.t('Select Action')}
emptyLabel={$i18n.t('No actions found')}
variant="dropdown"
on:select={(e) => {
toggleAction(e.detail);
}}
on:enableall={(e) => {
selectedActionIds = [
...new Set([...selectedActionIds, ...e.detail.map((action) => action.id)])
];
}}
/>
{/if}
</div>
<div class="flex flex-col">
<TypeaheadSelector
id="model-actions-selector"
items={availableActions}
className="w-48 max-w-full"
placeholder={$i18n.t('Search actions')}
on:select={(e) => {
selectAction(e.detail);
}}
/>
<div class=" flex items-center flex-wrap">
<div class=" flex items-center flex-wrap mt-1">
{#each selectedActions as action, actionIdx}
<div class=" flex items-center gap-2 mr-3">
<div class="self-center flex items-center">
@@ -71,5 +84,9 @@
{/each}
</div>
</div>
<div class=" text-xs dark:text-gray-700">
{$i18n.t('To select actions here, add them to the "Functions" workspace first.')}
</div>
</div>
{/if}
@@ -18,34 +18,45 @@
export let selectedFilterIds: string[] = [];
$: selectedFilters = filters.filter((filter) => selectedFilterIds.includes(filter.id));
$: availableFilters = filters.filter((filter) => !selectedFilterIds.includes(filter.id));
const selectFilter = (filter: Filter) => {
selectedFilterIds = [...selectedFilterIds, filter.id];
const toggleFilter = (filter: Filter) => {
selectedFilterIds = selectedFilterIds.includes(filter.id)
? selectedFilterIds.filter((id) => id !== filter.id)
: [...selectedFilterIds, filter.id];
};
</script>
<div>
<div class="flex w-full justify-between mb-1">
<div class="flex w-full items-center gap-2 mb-1">
<div class=" self-center text-xs text-gray-500">{$i18n.t('Default Filters')}</div>
{#if filters.length > 0}
<TypeaheadSelector
id="model-default-filters-selector"
items={filters.map((filter) => ({
...filter,
description: filter.meta?.description
}))}
selectedIds={selectedFilterIds}
placeholder={$i18n.t('Search filters')}
triggerLabel={$i18n.t('Select Filter')}
emptyLabel={$i18n.t('No filters found')}
variant="dropdown"
on:select={(e) => {
toggleFilter(e.detail);
}}
on:enableall={(e) => {
selectedFilterIds = [
...new Set([...selectedFilterIds, ...e.detail.map((filter) => filter.id)])
];
}}
/>
{/if}
</div>
<div class="flex flex-col">
{#if filters.length > 0}
<TypeaheadSelector
id="model-default-filters-selector"
items={availableFilters.map((filter) => ({
...filter,
description: filter.meta?.description
}))}
className="w-48 max-w-full"
placeholder={$i18n.t('Search filters')}
on:select={(e) => {
selectFilter(e.detail);
}}
/>
<div class=" flex items-center flex-wrap">
<div class=" flex items-center flex-wrap mt-1">
{#each selectedFilters as filter}
{@const isSelected = selectedFilterIds.includes(filter.id)}
<div class=" flex items-center gap-2 mr-3">
@@ -74,4 +85,8 @@
</div>
{/if}
</div>
<div class=" text-xs dark:text-gray-700">
{$i18n.t('To select default filters here, enable toggleable filters for this model first.')}
</div>
</div>
@@ -18,40 +18,50 @@
export let filters: Filter[] = [];
export let selectedFilterIds: string[] = [];
$: selectableFilters = filters.filter((filter) => !filter.is_global);
$: selectedFilters = filters.filter(
(filter) => filter.is_global || selectedFilterIds.includes(filter.id)
);
$: availableFilters = filters.filter(
(filter) => !filter.is_global && !selectedFilterIds.includes(filter.id)
);
const selectFilter = (filter: Filter) => {
selectedFilterIds = [...selectedFilterIds, filter.id];
const toggleFilter = (filter: Filter) => {
selectedFilterIds = selectedFilterIds.includes(filter.id)
? selectedFilterIds.filter((id) => id !== filter.id)
: [...selectedFilterIds, filter.id];
};
</script>
{#if filters.length > 0}
<div>
<div class="flex w-full justify-between mb-1">
<div class="flex w-full items-center gap-2 mb-1">
<div class=" self-center text-xs text-gray-500">{$i18n.t('Filters')}</div>
{#if selectableFilters.length > 0}
<TypeaheadSelector
id="model-filters-selector"
items={selectableFilters.map((filter) => ({
...filter,
description: filter.meta?.description
}))}
selectedIds={selectedFilterIds}
placeholder={$i18n.t('Search filters')}
triggerLabel={$i18n.t('Select Filter')}
emptyLabel={$i18n.t('No filters found')}
variant="dropdown"
on:select={(e) => {
toggleFilter(e.detail);
}}
on:enableall={(e) => {
selectedFilterIds = [
...new Set([...selectedFilterIds, ...e.detail.map((filter) => filter.id)])
];
}}
/>
{/if}
</div>
<!-- TODO: Filter order matters -->
<div class="flex flex-col">
<TypeaheadSelector
id="model-filters-selector"
items={availableFilters.map((filter) => ({
...filter,
description: filter.meta?.description
}))}
className="w-48 max-w-full"
placeholder={$i18n.t('Search filters')}
on:select={(e) => {
selectFilter(e.detail);
}}
/>
<div class=" flex items-center flex-wrap">
<div class=" flex items-center flex-wrap mt-1">
{#each selectedFilters as filter}
{@const isSelected = filter.is_global || selectedFilterIds.includes(filter.id)}
<div class=" flex items-center gap-2 mr-3">
@@ -82,5 +92,9 @@
{/each}
</div>
</div>
<div class=" text-xs dark:text-gray-700">
{$i18n.t('To select filters here, add them to the "Functions" workspace first.')}
</div>
</div>
{/if}
@@ -3,6 +3,7 @@
import { saveAs } from 'file-saver';
import { toast } from 'svelte-sonner';
import Plus from '$lib/components/icons/Plus.svelte';
import XMark from '$lib/components/icons/XMark.svelte';
import Tooltip from '$lib/components/common/Tooltip.svelte';
const i18n = getContext('i18n');
@@ -26,13 +27,13 @@
}
</script>
<div class=" space-y-3">
<div class="flex w-full justify-between mb-1.5">
<div class=" self-center text-xs flex-1 shrink-0 w-full">
<div class="space-y-2">
<div class="mb-1 flex h-6 w-full items-center justify-between">
<div class="min-w-0 flex-1 self-center text-xs text-gray-500 dark:text-gray-400">
{$i18n.t('Default Prompt Suggestions')}
</div>
<div class="flex justify-end gap-2">
<div class="flex shrink-0 items-center justify-end gap-1.5">
<input
id="prompt-suggestions-import-input"
type="file"
@@ -75,7 +76,7 @@
/>
<button
class="flex text-xs items-center space-x-1 py-1 rounded-xl bg-transparent dark:text-gray-200 transition"
class="flex items-center rounded-xl bg-transparent px-1 py-0.5 text-xs text-gray-500 transition hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
type="button"
on:click={() => {
const input = document.getElementById('prompt-suggestions-import-input');
@@ -84,14 +85,14 @@
}
}}
>
<div class=" self-center font-normal line-clamp-1">
<div class="line-clamp-1 self-center font-normal">
{$i18n.t('Import')}
</div>
</button>
{#if promptSuggestions.length}
<button
class="flex text-xs items-center space-x-1 py-1 rounded-xl bg-transparent dark:text-gray-200 transition"
class="flex items-center rounded-xl bg-transparent px-1 py-0.5 text-xs text-gray-500 transition hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
type="button"
on:click={async () => {
let blob = new Blob([JSON.stringify(promptSuggestions)], {
@@ -100,89 +101,85 @@
saveAs(blob, `prompt-suggestions-export-${Date.now()}.json`);
}}
>
<div class=" self-center font-normal line-clamp-1">
<div class="line-clamp-1 self-center font-normal">
{$i18n.t('Export')}
</div>
</button>
{/if}
<button
class=" px-1.5 rounded-xl transition font-normal text-sm flex items-center"
class="flex size-6 items-center justify-center text-gray-500 transition hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
type="button"
aria-label={$i18n.t('Add prompt suggestion')}
on:click={() => {
if (promptSuggestions.length === 0 || promptSuggestions.at(-1).content !== '') {
promptSuggestions = [...promptSuggestions, { content: '', title: ['', ''] }];
}
}}
>
<Plus className="size-3" strokeWidth="2.5" />
<Plus className="size-3.5" strokeWidth="2.25" />
</button>
</div>
</div>
{#if _promptSuggestions.length > 0}
<div class="flex flex-col gap-2">
<div class="flex flex-col gap-1.5">
{#each _promptSuggestions as prompt, promptIdx}
<div
class=" flex border rounded-2xl border-gray-100/30 dark:border-gray-850/30 bg-transparent p-2"
class="flex gap-1 rounded-lg border border-gray-100/40 bg-transparent px-2 py-1 dark:border-gray-850/50"
>
<div class="flex flex-col md:flex-row w-full gap-1 md:gap-2 px-2">
<div class="gap-0.5 min-w-60">
<div class="flex min-w-0 flex-1 flex-col gap-0.5">
<div class="grid min-w-0 gap-1 md:grid-cols-2 md:gap-1.5">
<Tooltip content={$i18n.t('e.g. Tell me a fun fact')} placement="top-start">
<input
class="text-sm w-full bg-transparent outline-hidden"
class="w-full bg-transparent text-[13px] leading-5 text-gray-700 outline-hidden placeholder:text-gray-300 dark:text-gray-200 dark:placeholder:text-gray-700"
placeholder={$i18n.t('Title')}
aria-label={$i18n.t('Title')}
bind:value={prompt.title[0]}
/>
</Tooltip>
<Tooltip content={$i18n.t('e.g. about the Roman Empire')} placement="top-start">
<input
class="text-sm w-full bg-transparent outline-hidden text-gray-600 dark:text-gray-400"
class="w-full bg-transparent text-[13px] leading-5 text-gray-500 outline-hidden placeholder:text-gray-300 dark:text-gray-500 dark:placeholder:text-gray-700"
placeholder={$i18n.t('Subtitle')}
aria-label={$i18n.t('Subtitle')}
bind:value={prompt.title[1]}
/>
</Tooltip>
</div>
<Tooltip
className="w-full self-center items-center flex"
className="flex min-w-0"
content={$i18n.t('e.g. Tell me a fun fact about the Roman Empire')}
placement="top-start"
>
<textarea
class="text-sm w-full bg-transparent outline-hidden resize-none"
placeholder={$i18n.t('Prompt')}
rows="2"
class="min-h-5 w-full resize-none bg-transparent text-[13px] leading-5 text-gray-700 outline-hidden placeholder:text-gray-300 dark:text-gray-200 dark:placeholder:text-gray-700"
placeholder={$i18n.t('Content')}
aria-label={$i18n.t('Content')}
rows="1"
bind:value={prompt.content}
/>
</Tooltip>
</div>
<button
class="p-1 self-start"
class="flex size-6 shrink-0 items-center justify-center text-gray-400 opacity-70 transition hover:text-gray-700 hover:opacity-100 dark:text-gray-600 dark:hover:text-gray-300"
type="button"
aria-label={$i18n.t('Remove prompt suggestion')}
on:click={() => {
promptSuggestions.splice(promptIdx, 1);
promptSuggestions = promptSuggestions;
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="w-4 h-4"
>
<path
d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
/>
</svg>
<XMark className="size-3.5" />
</button>
</div>
{/each}
</div>
{:else}
<div class="text-xs text-center w-full text-gray-500 mb-1.5">
<div class="mb-1.5 w-full text-center text-xs text-gray-500 dark:text-gray-600">
{$i18n.t('No suggestion prompts')}
</div>
{/if}