fix(itinerary): fix route optimization reactivity and replace api key provider dropdown with AI LLM providers
- fix optimizeDayOrder() dual-update: directly set days[dayIndex].items + days before saveReorderedItems() so it reads the correct post-optimization order synchronously (Svelte 4 batches reactive statements; days wasn't updated before save read it) - also patch collection.itinerary order values so reactive rebuild uses new order - replace single google_maps <option> with 8 AI LLM provider options (anthropic, openai, gemini, ollama, groq, mistral, github_models, openrouter) - add getApiKeyProviderLabel() helper for saved key display with google_maps fallback - add i18n keys for all new provider labels in en.json and de.json
This commit is contained in:
@@ -1191,8 +1191,22 @@
|
||||
return !getCoordinatesFromItineraryItem(item);
|
||||
});
|
||||
|
||||
days[dayIndex].items = [...optimizedPath, ...nonCoordinateItems, ...shadowItems];
|
||||
const newDayItems = [...optimizedPath, ...nonCoordinateItems, ...shadowItems];
|
||||
|
||||
// Patch collection.itinerary order values so the reactive $: days rebuild
|
||||
// uses the new order when it eventually fires.
|
||||
newDayItems.forEach((item, index) => {
|
||||
const itineraryItem = collection.itinerary?.find((it) => it.id === item.id);
|
||||
if (itineraryItem) {
|
||||
itineraryItem.order = index;
|
||||
}
|
||||
});
|
||||
// Also directly set days so saveReorderedItems() reads the correct order synchronously
|
||||
// (Svelte 4 batches reactive statements; days isn't updated yet when saveReorderedItems runs)
|
||||
days[dayIndex].items = newDayItems;
|
||||
days = [...days];
|
||||
// Trigger collection reactivity so the eventual reactive rebuild uses new orders
|
||||
collection = { ...collection, itinerary: [...(collection.itinerary || [])] };
|
||||
|
||||
isSavingOrder = true;
|
||||
savingDay = day.date;
|
||||
|
||||
@@ -748,6 +748,14 @@
|
||||
"no_api_keys_saved": "Noch keine API-Schlüssel gespeichert.",
|
||||
"add_api_key": "API-Schlüssel hinzufügen",
|
||||
"provider": "Anbieter",
|
||||
"api_key_provider_anthropic": "Anthropic",
|
||||
"api_key_provider_openai": "OpenAI",
|
||||
"api_key_provider_gemini": "Google Gemini",
|
||||
"api_key_provider_ollama": "Ollama (Lokal)",
|
||||
"api_key_provider_groq": "Groq",
|
||||
"api_key_provider_mistral": "Mistral AI",
|
||||
"api_key_provider_github_models": "GitHub Models",
|
||||
"api_key_provider_openrouter": "OpenRouter",
|
||||
"api_key_provider_google_places": "Google Places API",
|
||||
"api_key_value": "API-Schlüssel",
|
||||
"api_key_value_placeholder": "Geben Sie Ihren API-Schlüssel ein",
|
||||
|
||||
@@ -745,6 +745,14 @@
|
||||
"no_api_keys_saved": "No API keys saved yet.",
|
||||
"add_api_key": "Add API Key",
|
||||
"provider": "Provider",
|
||||
"api_key_provider_anthropic": "Anthropic",
|
||||
"api_key_provider_openai": "OpenAI",
|
||||
"api_key_provider_gemini": "Google Gemini",
|
||||
"api_key_provider_ollama": "Ollama (Local)",
|
||||
"api_key_provider_groq": "Groq",
|
||||
"api_key_provider_mistral": "Mistral AI",
|
||||
"api_key_provider_github_models": "GitHub Models",
|
||||
"api_key_provider_openrouter": "OpenRouter",
|
||||
"api_key_provider_google_places": "Google Places API",
|
||||
"api_key_value": "API Key",
|
||||
"api_key_value_placeholder": "Enter your API key",
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
};
|
||||
let userApiKeys: UserAPIKey[] = data.props.apiKeys ?? [];
|
||||
let apiKeysConfigError: string | null = data.props.apiKeysConfigError ?? null;
|
||||
let newApiKeyProvider = 'google_maps';
|
||||
let newApiKeyProvider = 'anthropic';
|
||||
let newApiKeyValue = '';
|
||||
let isSavingApiKey = false;
|
||||
let deletingApiKeyId: string | null = null;
|
||||
@@ -53,6 +53,30 @@
|
||||
let isLoadingMcpToken = false;
|
||||
let activeSection: string = 'profile';
|
||||
|
||||
const API_KEY_PROVIDER_OPTIONS = [
|
||||
{ value: 'anthropic', labelKey: 'settings.api_key_provider_anthropic' },
|
||||
{ value: 'openai', labelKey: 'settings.api_key_provider_openai' },
|
||||
{ value: 'gemini', labelKey: 'settings.api_key_provider_gemini' },
|
||||
{ value: 'ollama', labelKey: 'settings.api_key_provider_ollama' },
|
||||
{ value: 'groq', labelKey: 'settings.api_key_provider_groq' },
|
||||
{ value: 'mistral', labelKey: 'settings.api_key_provider_mistral' },
|
||||
{ value: 'github_models', labelKey: 'settings.api_key_provider_github_models' },
|
||||
{ value: 'openrouter', labelKey: 'settings.api_key_provider_openrouter' }
|
||||
];
|
||||
|
||||
function getApiKeyProviderLabel(provider: string): string {
|
||||
const option = API_KEY_PROVIDER_OPTIONS.find((entry) => entry.value === provider);
|
||||
if (option) {
|
||||
return $t(option.labelKey);
|
||||
}
|
||||
|
||||
if (provider === 'google_maps') {
|
||||
return $t('settings.api_key_provider_google_places');
|
||||
}
|
||||
|
||||
return provider;
|
||||
}
|
||||
|
||||
// typed alias for social providers to satisfy TypeScript
|
||||
let socialProviders: Provider[] = data.props.socialProviders ?? [];
|
||||
|
||||
@@ -1586,7 +1610,7 @@
|
||||
{#each userApiKeys as apiKey}
|
||||
<div class="flex items-center justify-between gap-4 p-4 bg-base-100 rounded-lg">
|
||||
<div>
|
||||
<div class="font-medium">{apiKey.provider}</div>
|
||||
<div class="font-medium">{getApiKeyProviderLabel(apiKey.provider)}</div>
|
||||
<div class="text-sm text-base-content/70 font-mono">
|
||||
{apiKey.masked_api_key}
|
||||
</div>
|
||||
@@ -1619,9 +1643,11 @@
|
||||
class="select select-bordered select-primary w-full"
|
||||
bind:value={newApiKeyProvider}
|
||||
>
|
||||
<option value="google_maps">{$t('settings.api_key_provider_google_places')}</option>
|
||||
</select>
|
||||
</div>
|
||||
{#each API_KEY_PROVIDER_OPTIONS as option}
|
||||
<option value={option.value}>{$t(option.labelKey)}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label" for="api-key-value">
|
||||
<span class="label-text font-medium">{$t('settings.api_key_value')}</span>
|
||||
|
||||
Reference in New Issue
Block a user