From 705c90debda87451fcdc32f15f086080ab7dc5f9 Mon Sep 17 00:00:00 2001 From: Guilhem Date: Thu, 30 Jul 2026 23:40:03 +0200 Subject: [PATCH] feat(frontend): add missing resource type icons and show them in the resource picker (#10407) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(frontend): add missing resource type icons and show them in the picker Anthropic, DeepSeek, OpenRouter, Google AI (Gemini) and Ultravox resource types rendered as a blank grey circle. Add their marks and wire up two icons that already existed in the repo but were never imported. Unmapped resource types now fall back to the generic resource glyph instead of the grey circle, and the resource picker shows the icon before the path — both in the dropdown rows and inside the input — omitting it entirely, with no reserved padding, when the type has no icon. Co-Authored-By: Claude Opus 5 (1M context) * fix(frontend): correct gemini gradient units and reuse the icon resolver The Gemini gradient omitted gradientUnits, so its 0..24 coordinates were read as objectBoundingBox fractions and the whole mark collapsed onto a 4% slice of the ramp — a flat purple. Pin it to userSpaceOnUse like every other gradient icon in the directory. Index the resource list by path once instead of scanning it per dropdown row, fold the two remaining inline copies of the icon lookup into appIconComponent, and drop the sendflake key — no resource type by that name exists. Co-Authored-By: Claude Opus 5 (1M context) * style(frontend): shrink the resource picker icon to 14px Co-Authored-By: Claude Opus 5 (1M context) * style(frontend): drop the redundant frame around the ai providers list SettingCard already supplies p-4, rounded-md and bg-surface-tertiary, so the wrapper repeated all three and added a border, nesting a card inside a card. Co-Authored-By: Claude Opus 5 (1M context) * fix(frontend): keep the unregistered snowflake mark, extend the card fix SendflakeIcon is the Snowflake logo under a misleading filename, not a different product; SnowflakeIcon is the same logo with a baked-in ® that shrinks and off-centres the flake and turns to a smudge at 14-24px. Leave the mapping where it was. Apply the card-in-card removal to the two InstanceFallbackSettings cards that stack directly above the AI providers one, so the frames stay consistent. Co-Authored-By: Claude Opus 5 (1M context) * fix(frontend): make the ansible mark legible on dark surfaces Mapping `ansible` renders this icon for the first time, and its near-black disc disappears into the dark surface, leaving only the white "A" counter floating. Co-Authored-By: Claude Opus 5 (1M context) --------- Co-authored-by: Claude Opus 5 (1M context) --- .../lib/components/IconedResourceType.svelte | 16 +++---- .../src/lib/components/ResourcePicker.svelte | 18 +++++++ .../lib/components/home/ListFilters.svelte | 8 +--- .../components/home/ListFiltersQuick.svelte | 19 ++++---- .../lib/components/icons/AnsibleIcon.svelte | 9 ++-- .../lib/components/icons/AnthropicIcon.svelte | 14 ++++++ .../lib/components/icons/DeepSeekIcon.svelte | 14 ++++++ .../lib/components/icons/GoogleAiIcon.svelte | 29 +++++++++++ .../components/icons/OpenRouterIcon.svelte | 14 ++++++ .../lib/components/icons/UltravoxIcon.svelte | 48 +++++++++++++++++++ frontend/src/lib/components/icons/index.ts | 26 ++++++++++ .../src/lib/components/select/Select.svelte | 14 +++++- .../workspaceSettings/AISettings.svelte | 2 +- .../InstanceFallbackSettings.svelte | 4 +- 14 files changed, 202 insertions(+), 33 deletions(-) create mode 100644 frontend/src/lib/components/icons/AnthropicIcon.svelte create mode 100644 frontend/src/lib/components/icons/DeepSeekIcon.svelte create mode 100644 frontend/src/lib/components/icons/GoogleAiIcon.svelte create mode 100644 frontend/src/lib/components/icons/OpenRouterIcon.svelte create mode 100644 frontend/src/lib/components/icons/UltravoxIcon.svelte diff --git a/frontend/src/lib/components/IconedResourceType.svelte b/frontend/src/lib/components/IconedResourceType.svelte index 056af6c320..996cfb2a79 100644 --- a/frontend/src/lib/components/IconedResourceType.svelte +++ b/frontend/src/lib/components/IconedResourceType.svelte @@ -1,6 +1,6 @@ @@ -56,7 +50,9 @@ {:else} - + + + {/if} {#if !silent && after} {name} diff --git a/frontend/src/lib/components/ResourcePicker.svelte b/frontend/src/lib/components/ResourcePicker.svelte index 60b15277e0..8342bbecf6 100644 --- a/frontend/src/lib/components/ResourcePicker.svelte +++ b/frontend/src/lib/components/ResourcePicker.svelte @@ -11,6 +11,7 @@ import Select from './select/Select.svelte' import ExploreAssetButton, { assetCanBeExplored } from './ExploreAssetButton.svelte' import DropdownV2 from './DropdownV2.svelte' + import { appIconComponent } from './icons' interface Props { initialValue?: string | undefined @@ -186,6 +187,8 @@ let resourceEditor: ResourceEditorDrawer | undefined = $state() let hovering = $state(false) let isDatatableSelected = $derived(value?.startsWith('datatable://') ?? false) + let typeByPath = $derived(new Map(collection.map((x) => [x.value, x.type]))) + let SelectedIcon = $derived(appIconComponent(typeByPath.get(value!))) +{#snippet selectedIconSnippet()} + {#if SelectedIcon} + + {/if} +{/snippet} +
+ {#snippet startSnippet({ item })} + {@const Icon = appIconComponent(typeByPath.get(item.value))} + {#if Icon} + + + + {/if} + {/snippet} {#snippet endSnippet({ item, close })} {#if !item.value?.startsWith('datatable://')}
{/if} + {#if inputLeadingSnippet} +
+ {@render inputLeadingSnippet()} +
+ {/if} + {#if tooltip}
{tooltip} @@ -204,6 +214,7 @@ 'focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0', open ? '' : 'cursor-pointer', loading || (clearable && !disabled && value) || RightIcon ? 'pr-7' : '', + inputLeadingSnippet ? 'pl-7' : '', 'empty:before:content-[attr(data-placeholder)]', !value ? 'empty:before:text-hint' : 'empty:before:text-primary', disabled && '!bg-surface-disabled !border-transparent !text-disabled pointer-events-none', @@ -244,6 +255,7 @@ // Show value as placeholder when opening the dropdown and the search is empty !value ? 'placeholder-hint' : '!placeholder-primary', loading || (clearable && !disabled && value) || RightIcon ? 'pr-8' : '', + inputLeadingSnippet ? 'pl-7' : '', inputClass ?? '' )} autocomplete="off" diff --git a/frontend/src/lib/components/workspaceSettings/AISettings.svelte b/frontend/src/lib/components/workspaceSettings/AISettings.svelte index f44059e395..48e3fb7f15 100644 --- a/frontend/src/lib/components/workspaceSettings/AISettings.svelte +++ b/frontend/src/lib/components/workspaceSettings/AISettings.svelte @@ -387,7 +387,7 @@ {/if} {#if showWorkspaceOverrideEditor} -
+
{#each Object.entries(AI_PROVIDERS) as [provider, details] (provider)}
diff --git a/frontend/src/lib/components/workspaceSettings/InstanceFallbackSettings.svelte b/frontend/src/lib/components/workspaceSettings/InstanceFallbackSettings.svelte index 2bfe4b8790..c6eee8ff8b 100644 --- a/frontend/src/lib/components/workspaceSettings/InstanceFallbackSettings.svelte +++ b/frontend/src/lib/components/workspaceSettings/InstanceFallbackSettings.svelte @@ -30,7 +30,7 @@ {#if instanceAiSummary} -
+

This workspace is currently using the instance AI defaults shown below.

@@ -91,7 +91,7 @@ {/if} -
+

Create workspace-specific AI settings only if this workspace needs to override the active instance defaults.