chat worked
This commit is contained in:
@@ -11,13 +11,17 @@
|
||||
|
||||
/** @type {Object} */
|
||||
let {
|
||||
documentation = null,
|
||||
content = "",
|
||||
type = 'markdown',
|
||||
format = 'text',
|
||||
onSave = async () => {},
|
||||
onCancel = () => {},
|
||||
} = $props();
|
||||
|
||||
let previewDoc = $derived(documentation || content);
|
||||
|
||||
let isSaving = false;
|
||||
let isSaving = $state(false);
|
||||
|
||||
async function handleSave() {
|
||||
isSaving = true;
|
||||
@@ -31,14 +35,14 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if documentation}
|
||||
{#if previewDoc}
|
||||
<div class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||
<div class="bg-white p-6 rounded-lg shadow-xl w-full max-w-2xl max-h-[90vh] flex flex-col">
|
||||
<h3 class="text-lg font-semibold mb-4">{$t.llm.doc_preview_title}</h3>
|
||||
|
||||
<div class="flex-1 overflow-y-auto mb-6 prose prose-sm max-w-none border rounded p-4 bg-gray-50">
|
||||
<h4 class="text-md font-bold text-gray-800 mb-2">{$t.llm.dataset_desc}</h4>
|
||||
<p class="text-gray-700 mb-4 whitespace-pre-wrap">{documentation.description || 'No description generated.'}</p>
|
||||
<p class="text-gray-700 mb-4 whitespace-pre-wrap">{previewDoc.description || 'No description generated.'}</p>
|
||||
|
||||
<h4 class="text-md font-bold text-gray-800 mb-2">{$t.llm.column_doc}</h4>
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
@@ -49,7 +53,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-200">
|
||||
{#each Object.entries(documentation.columns || {}) as [name, desc]}
|
||||
{#each Object.entries(previewDoc.columns || {}) as [name, desc]}
|
||||
<tr>
|
||||
<td class="px-3 py-2 text-sm font-mono text-gray-900">{name}</td>
|
||||
<td class="px-3 py-2 text-sm text-gray-700">{desc}</td>
|
||||
@@ -62,14 +66,14 @@
|
||||
<div class="flex justify-end gap-3">
|
||||
<button
|
||||
class="px-4 py-2 border rounded hover:bg-gray-50"
|
||||
on:click={onCancel}
|
||||
onclick={onCancel}
|
||||
disabled={isSaving}
|
||||
>
|
||||
{$t.llm.cancel}
|
||||
</button>
|
||||
<button
|
||||
class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 disabled:opacity-50"
|
||||
on:click={handleSave}
|
||||
onclick={handleSave}
|
||||
disabled={isSaving}
|
||||
>
|
||||
{isSaving ? $t.llm.applying : $t.llm.apply_doc}
|
||||
@@ -79,4 +83,4 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- [/DEF:DocPreview:Component] -->
|
||||
<!-- [/DEF:DocPreview:Component] -->
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
-->
|
||||
|
||||
<script>
|
||||
import { onMount } from "svelte";
|
||||
import { t } from "../../lib/i18n";
|
||||
import { requestApi } from "../../lib/api";
|
||||
|
||||
/** @type {Array} */
|
||||
let { providers = [], onSave = () => {} } = $props();
|
||||
export let providers = [];
|
||||
export let onSave = () => {};
|
||||
|
||||
let editingProvider = null;
|
||||
let showForm = false;
|
||||
@@ -43,8 +43,18 @@
|
||||
}
|
||||
|
||||
function handleEdit(provider) {
|
||||
console.log("[ProviderConfig][Action] Editing provider", provider?.id);
|
||||
editingProvider = provider;
|
||||
formData = { ...provider, api_key: "" }; // Don't populate key for security
|
||||
// Normalize provider fields to editable form shape.
|
||||
formData = {
|
||||
name: provider?.name ?? "",
|
||||
provider_type: provider?.provider_type ?? "openai",
|
||||
base_url: provider?.base_url ?? "https://api.openai.com/v1",
|
||||
api_key: "",
|
||||
default_model: provider?.default_model ?? "gpt-4o",
|
||||
is_active: Boolean(provider?.is_active),
|
||||
};
|
||||
testStatus = { type: "", message: "" };
|
||||
showForm = true;
|
||||
}
|
||||
|
||||
@@ -121,19 +131,22 @@
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h2 class="text-xl font-bold">{$t.llm.providers_title}</h2>
|
||||
<button
|
||||
type="button"
|
||||
class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 transition"
|
||||
on:click={() => {
|
||||
on:click|preventDefault={() => {
|
||||
resetForm();
|
||||
showForm = true;
|
||||
}}
|
||||
>
|
||||
{$t.llm.add_provider}
|
||||
{$t.llm.add_provider}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{#if showForm}
|
||||
<div
|
||||
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<div class="bg-white p-6 rounded-lg shadow-xl w-full max-w-md">
|
||||
<h3 class="text-lg font-semibold mb-4">
|
||||
@@ -241,23 +254,26 @@
|
||||
|
||||
<div class="mt-6 flex justify-between gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="px-4 py-2 border rounded hover:bg-gray-50 flex-1"
|
||||
on:click={() => {
|
||||
on:click|preventDefault={() => {
|
||||
showForm = false;
|
||||
}}
|
||||
>
|
||||
{$t.llm.cancel}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="px-4 py-2 bg-gray-600 text-white rounded hover:bg-gray-700 flex-1"
|
||||
disabled={isTesting}
|
||||
on:click={testConnection}
|
||||
on:click|preventDefault={testConnection}
|
||||
>
|
||||
{isTesting ? $t.llm.testing : $t.llm.test}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 flex-1"
|
||||
on:click={handleSubmit}
|
||||
on:click|preventDefault={handleSubmit}
|
||||
>
|
||||
{$t.llm.save}
|
||||
</button>
|
||||
@@ -286,14 +302,16 @@
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="text-sm text-blue-600 hover:underline"
|
||||
on:click={() => handleEdit(provider)}
|
||||
on:click|preventDefault|stopPropagation={() => handleEdit(provider)}
|
||||
>
|
||||
{$t.common.edit}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class={`text-sm ${provider.is_active ? "text-orange-600" : "text-green-600"} hover:underline`}
|
||||
on:click={() => toggleActive(provider)}
|
||||
on:click|preventDefault|stopPropagation={() => toggleActive(provider)}
|
||||
>
|
||||
{provider.is_active ? "Deactivate" : "Activate"}
|
||||
</button>
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// [DEF:frontend.src.components.llm.__tests__.provider_config_integration:Module]
|
||||
// @TIER: STANDARD
|
||||
// @SEMANTICS: llm, provider-config, integration-test, edit-flow
|
||||
// @PURPOSE: Protect edit-button interaction contract in LLM provider settings UI.
|
||||
// @LAYER: UI Tests
|
||||
// @RELATION: VERIFIES -> frontend/src/components/llm/ProviderConfig.svelte
|
||||
// @INVARIANT: Edit action keeps explicit click handler and opens normalized edit form.
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
const COMPONENT_PATH = path.resolve(
|
||||
process.cwd(),
|
||||
'src/components/llm/ProviderConfig.svelte',
|
||||
);
|
||||
|
||||
// [DEF:provider_config_edit_contract_tests:Function]
|
||||
// @TIER: STANDARD
|
||||
// @PURPOSE: Validate edit button handler wiring and normalized edit form state mapping.
|
||||
// @PRE: ProviderConfig component source exists in expected path.
|
||||
// @POST: Contract checks ensure edit click cannot degrade into no-op flow.
|
||||
describe('ProviderConfig edit interaction contract', () => {
|
||||
it('keeps explicit edit click handler with guarded button semantics', () => {
|
||||
const source = fs.readFileSync(COMPONENT_PATH, 'utf-8');
|
||||
|
||||
expect(source).toContain('type="button"');
|
||||
expect(source).toContain(
|
||||
"on:click|preventDefault|stopPropagation={() => handleEdit(provider)}",
|
||||
);
|
||||
});
|
||||
|
||||
it('normalizes provider payload into editable form shape', () => {
|
||||
const source = fs.readFileSync(COMPONENT_PATH, 'utf-8');
|
||||
|
||||
expect(source).toContain('formData = {');
|
||||
expect(source).toContain('name: provider?.name ?? ""');
|
||||
expect(source).toContain('provider_type: provider?.provider_type ?? "openai"');
|
||||
expect(source).toContain('default_model: provider?.default_model ?? "gpt-4o"');
|
||||
expect(source).toContain('showForm = true;');
|
||||
});
|
||||
});
|
||||
// [/DEF:provider_config_edit_contract_tests:Function]
|
||||
// [/DEF:frontend.src.components.llm.__tests__.provider_config_integration:Module]
|
||||
Reference in New Issue
Block a user