Protokoll #22279

ID22279
Zeitstempel2025-12-27 12:05:42.300240
Clientroot
IP145.224.72.140
Modellclaude-sonnet-4-20250514
Statuscompleted
Tokens7,175 (Input: 1,490, Output: 5,685)
Dauer97 ms
Request-Zeit2025-12-27 12:05:42.300240
Response-Zeit2025-12-27 12:05:42.397729

Request

{
    "event": "PreToolUse",
    "tool_name": "Edit",
    "tool_input": {
        "file_path": "\/var\/www\/dev.campus.systemische-tools.de\/src\/View\/content-pipeline\/show.php",
        "old_string": "<script>\ndocument.addEventListener('DOMContentLoaded', function() {\n    const pipelineId = <?= (int) $pipeline['id'] ?>;\n\n    \/\/ Model-Dropdowns\n    document.querySelectorAll('.model-cell select').forEach(select => {\n        select.addEventListener('change', async function() {\n            const row = this.closest('tr');\n            const stepId = row.dataset.stepId;\n            const model = this.value;\n\n            this.classList.add('is-saving');\n\n            try {\n                const response = await fetch(`\/content-pipeline\/${pipelineId}\/steps\/${stepId}\/model`, {\n                    method: 'POST',\n                    headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\n                    body: 'model=' + encodeURIComponent(model)\n                });\n\n                const data = await response.json();\n\n                if (data.success) {\n                    this.classList.remove('is-saving');\n                    this.classList.add('is-saved');\n                    setTimeout(() => this.classList.remove('is-saved'), 500);\n\n                    \/\/ Speichere in localStorage für User-Präferenz\n                    localStorage.setItem('pipeline_default_model', model);\n                } else {\n                    alert('Fehler: ' + (data.error || 'Unbekannter Fehler'));\n                    this.classList.remove('is-saving');\n                }\n            } catch (error) {\n                alert('Speichern fehlgeschlagen: ' + error.message);\n                this.classList.remove('is-saving');\n            }\n        });\n    });\n\n    \/\/ User-Präferenz für neues Standard-Modell laden\n    const savedModel = localStorage.getItem('pipeline_default_model');\n    if (savedModel) {\n        console.log('Gespeichertes Standard-Modell:', savedModel);\n    }\n\n    \/\/ Collection-Dropdowns\n    document.querySelectorAll('.collection-select').forEach(select => {\n        select.addEventListener('change', async function() {\n            const stepId = this.dataset.stepId;\n            const collection = this.value;\n\n            this.classList.add('is-saving');\n\n            try {\n                const response = await fetch(`\/content-pipeline\/${pipelineId}\/steps\/${stepId}\/collection`, {\n                    method: 'POST',\n                    headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\n                    body: 'collection=' + encodeURIComponent(collection)\n                });\n\n                const data = await response.json();\n\n                if (data.success) {\n                    this.classList.remove('is-saving');\n                    this.classList.add('is-saved');\n                    setTimeout(() => this.classList.remove('is-saved'), 500);\n                } else {\n                    alert('Fehler: ' + (data.error || 'Unbekannter Fehler'));\n                    this.classList.remove('is-saving');\n                }\n            } catch (error) {\n                alert('Speichern fehlgeschlagen: ' + error.message);\n                this.classList.remove('is-saving');\n            }\n        });\n    });\n\n    \/\/ Inline-Edit für Quelle und Dateitypen\n    document.querySelectorAll('.config-list__value.editable').forEach(el => {\n        el.addEventListener('click', function() {\n            if (this.querySelector('input')) return;\n\n            const field = this.dataset.field;\n            const currentValue = this.textContent.trim();\n            const originalEl = this;\n\n            const input = document.createElement('input');\n            input.type = 'text';\n            input.className = 'config-list__input';\n            input.value = currentValue;\n\n            originalEl.textContent = '';\n            originalEl.appendChild(input);\n            input.focus();\n            input.select();\n\n            async function saveValue() {\n                const newValue = input.value.trim();\n                if (newValue === currentValue) {\n                    originalEl.textContent = currentValue;\n                    return;\n                }\n\n                originalEl.classList.add('is-saving');\n\n                try {\n                    const response = await fetch(`\/content-pipeline\/${pipelineId}\/config`, {\n                        method: 'POST',\n                        headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\n                        body: field + '=' + encodeURIComponent(newValue)\n                    });\n\n                    const data = await response.json();\n\n                    if (data.success) {\n                        originalEl.textContent = newValue;\n                        originalEl.classList.remove('is-saving');\n                    } else {\n                        alert('Fehler: ' + (data.error || 'Unbekannter Fehler'));\n                        originalEl.textContent = currentValue;\n                        originalEl.classList.remove('is-saving');\n                    }\n                } catch (error) {\n                    alert('Speichern fehlgeschlagen: ' + error.message);\n                    originalEl.textContent = currentValue;\n                    originalEl.classList.remove('is-saving');\n                }\n            }\n\n            input.addEventListener('blur', saveValue);\n            input.addEventListener('keydown', function(e) {\n                if (e.key === 'Enter') {\n                    e.preventDefault();\n                    input.blur();\n                } else if (e.key === 'Escape') {\n                    originalEl.textContent = currentValue;\n                }\n            });\n        });\n    });\n});\n<\/script>\n\n<?php $content = ob_get_clean(); ?>",
        "new_string": "<?php $content = ob_get_clean(); ?>"
    }
}

Response

{
    "tool_response": {
        "filePath": "\/var\/www\/dev.campus.systemische-tools.de\/src\/View\/content-pipeline\/show.php",
        "oldString": "<script>\ndocument.addEventListener('DOMContentLoaded', function() {\n    const pipelineId = <?= (int) $pipeline['id'] ?>;\n\n    \/\/ Model-Dropdowns\n    document.querySelectorAll('.model-cell select').forEach(select => {\n        select.addEventListener('change', async function() {\n            const row = this.closest('tr');\n            const stepId = row.dataset.stepId;\n            const model = this.value;\n\n            this.classList.add('is-saving');\n\n            try {\n                const response = await fetch(`\/content-pipeline\/${pipelineId}\/steps\/${stepId}\/model`, {\n                    method: 'POST',\n                    headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\n                    body: 'model=' + encodeURIComponent(model)\n                });\n\n                const data = await response.json();\n\n                if (data.success) {\n                    this.classList.remove('is-saving');\n                    this.classList.add('is-saved');\n                    setTimeout(() => this.classList.remove('is-saved'), 500);\n\n                    \/\/ Speichere in localStorage für User-Präferenz\n                    localStorage.setItem('pipeline_default_model', model);\n                } else {\n                    alert('Fehler: ' + (data.error || 'Unbekannter Fehler'));\n                    this.classList.remove('is-saving');\n                }\n            } catch (error) {\n                alert('Speichern fehlgeschlagen: ' + error.message);\n                this.classList.remove('is-saving');\n            }\n        });\n    });\n\n    \/\/ User-Präferenz für neues Standard-Modell laden\n    const savedModel = localStorage.getItem('pipeline_default_model');\n    if (savedModel) {\n        console.log('Gespeichertes Standard-Modell:', savedModel);\n    }\n\n    \/\/ Collection-Dropdowns\n    document.querySelectorAll('.collection-select').forEach(select => {\n        select.addEventListener('change', async function() {\n            const stepId = this.dataset.stepId;\n            const collection = this.value;\n\n            this.classList.add('is-saving');\n\n            try {\n                const response = await fetch(`\/content-pipeline\/${pipelineId}\/steps\/${stepId}\/collection`, {\n                    method: 'POST',\n                    headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\n                    body: 'collection=' + encodeURIComponent(collection)\n                });\n\n                const data = await response.json();\n\n                if (data.success) {\n                    this.classList.remove('is-saving');\n                    this.classList.add('is-saved');\n                    setTimeout(() => this.classList.remove('is-saved'), 500);\n                } else {\n                    alert('Fehler: ' + (data.error || 'Unbekannter Fehler'));\n                    this.classList.remove('is-saving');\n                }\n            } catch (error) {\n                alert('Speichern fehlgeschlagen: ' + error.message);\n                this.classList.remove('is-saving');\n            }\n        });\n    });\n\n    \/\/ Inline-Edit für Quelle und Dateitypen\n    document.querySelectorAll('.config-list__value.editable').forEach(el => {\n        el.addEventListener('click', function() {\n            if (this.querySelector('input')) return;\n\n            const field = this.dataset.field;\n            const currentValue = this.textContent.trim();\n            const originalEl = this;\n\n            const input = document.createElement('input');\n            input.type = 'text';\n            input.className = 'config-list__input';\n            input.value = currentValue;\n\n            originalEl.textContent = '';\n            originalEl.appendChild(input);\n            input.focus();\n            input.select();\n\n            async function saveValue() {\n                const newValue = input.value.trim();\n                if (newValue === currentValue) {\n                    originalEl.textContent = currentValue;\n                    return;\n                }\n\n                originalEl.classList.add('is-saving');\n\n                try {\n                    const response = await fetch(`\/content-pipeline\/${pipelineId}\/config`, {\n                        method: 'POST',\n                        headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\n                        body: field + '=' + encodeURIComponent(newValue)\n                    });\n\n                    const data = await response.json();\n\n                    if (data.success) {\n                        originalEl.textContent = newValue;\n                        originalEl.classList.remove('is-saving');\n                    } else {\n                        alert('Fehler: ' + (data.error || 'Unbekannter Fehler'));\n                        originalEl.textContent = currentValue;\n                        originalEl.classList.remove('is-saving');\n                    }\n                } catch (error) {\n                    alert('Speichern fehlgeschlagen: ' + error.message);\n                    originalEl.textContent = currentValue;\n                    originalEl.classList.remove('is-saving');\n                }\n            }\n\n            input.addEventListener('blur', saveValue);\n            input.addEventListener('keydown', function(e) {\n                if (e.key === 'Enter') {\n                    e.preventDefault();\n                    input.blur();\n                } else if (e.key === 'Escape') {\n                    originalEl.textContent = currentValue;\n                }\n            });\n        });\n    });\n});\n<\/script>\n\n<?php $content = ob_get_clean(); ?>",
        "newString": "<?php $content = ob_get_clean(); ?>",
        "originalFile": "<?php ob_start(); ?>\n\n<h1>Pipeline: <?= htmlspecialchars($pipeline['name']) ?><\/h1>\n\n<?php if ($pipeline['is_default']): ?>\n<span class=\"badge badge--success\">Standard-Pipeline<\/span>\n<?php endif; ?>\n\n<div class=\"page-actions\">\n    <a href=\"\/content-pipeline\/<?= $pipeline['id'] ?>\/edit\" class=\"btn btn--secondary\">Bearbeiten<\/a>\n    <form action=\"\/content-pipeline\/<?= $pipeline['id'] ?>\/run\" method=\"POST\" style=\"display:inline;\">\n        <input type=\"hidden\" name=\"_csrf_token\" value=\"<?= htmlspecialchars($_SESSION['_csrf_token'] ?? '') ?>\">\n        <button type=\"submit\" class=\"btn btn--primary\">Pipeline starten<\/button>\n    <\/form>\n<\/div>\n\n<ul class=\"config-list\">\n    <li class=\"config-list__item\">\n        <span class=\"config-list__label\">Quelle:<\/span>\n        <input type=\"text\" name=\"source_path\" class=\"config-list__input config-list__input--inline\"\n               value=\"<?= htmlspecialchars($pipeline['source_path']) ?>\"\n               hx-post=\"\/content-pipeline\/<?= $pipeline['id'] ?>\/config\"\n               hx-headers='{\"X-CSRF-TOKEN\": \"<?= $csrfToken ?>\"}'\n               hx-trigger=\"blur, keyup[key=='Enter']\"\n               hx-swap=\"none\"\n               hx-disabled-elt=\"this\"\n               hx-on::after-request=\"this.classList.toggle('is-saved', event.detail.successful); setTimeout(() => this.classList.remove('is-saved'), 1000)\">\n    <\/li>\n    <li class=\"config-list__item\">\n        <span class=\"config-list__label\">Dateitypen:<\/span>\n        <input type=\"text\" name=\"extensions\" class=\"config-list__input config-list__input--inline\"\n               value=\"<?= implode(', ', $pipeline['extensions'] ?? []) ?>\"\n               hx-post=\"\/content-pipeline\/<?= $pipeline['id'] ?>\/config\"\n               hx-headers='{\"X-CSRF-TOKEN\": \"<?= $csrfToken ?>\"}'\n               hx-trigger=\"blur, keyup[key=='Enter']\"\n               hx-swap=\"none\"\n               hx-disabled-elt=\"this\"\n               hx-on::after-request=\"this.classList.toggle('is-saved', event.detail.successful); setTimeout(() => this.classList.remove('is-saved'), 1000)\">\n    <\/li>\n<\/ul>\n\n<h2>Pipeline-Schritte<\/h2>\n\n<table>\n    <thead>\n        <tr>\n            <th>#<\/th>\n            <th>Schritt<\/th>\n            <th>Phase<\/th>\n            <th>Modell<\/th>\n            <th>Zielspeicher<\/th>\n            <th>Konfiguration<\/th>\n        <\/tr>\n    <\/thead>\n    <tbody>\n        <?php foreach ($pipeline['steps'] as $step): ?>\n        <?php\n            $meta = $stepTypes[$step['step_type']] ?? ['label' => $step['step_type'], 'description' => '', 'phase' => '-', 'storage' => null];\n            $config = $step['config'] ?? [];\n\n            \/\/ Aktuelles Modell ermitteln (mit ollama: Prefix für Dropdown)\n            $currentModel = null;\n            $usesVision = $meta['uses_vision'] ?? false;\n            $usesLlm = $meta['uses_llm'] ?? false;\n\n            if (!empty($config['model'])) {\n                $isAnthropic = str_contains($config['model'], 'claude') || ($config['provider'] ?? '') === 'anthropic';\n                $currentModel = $isAnthropic ? $config['model'] : 'ollama:' . $config['model'];\n            }\n\n            \/\/ Config ohne model\/provider für kompaktere Anzeige\n            $displayConfig = array_filter($config, fn ($k) => !in_array($k, ['provider', 'model']), ARRAY_FILTER_USE_KEY);\n\n            \/\/ Zielspeicher mit dynamischen Werten ersetzen\n            $storage = $meta['storage'] ?? null;\n            if ($storage !== null && isset($config['collection'])) {\n                $storage = str_replace('{collection}', $config['collection'], $storage);\n            }\n            ?>\n        <tr data-step-id=\"<?= $step['id'] ?>\">\n            <td><?= $step['sort_order'] ?><\/td>\n            <td>\n                <strong><?= $meta['label'] ?><\/strong>\n                <br>\n                <small><?= $meta['description'] ?><\/small>\n            <\/td>\n            <td><?= $meta['phase'] ?><\/td>\n            <td class=\"model-cell\">\n                <?php if (!empty($meta['fixed_model'])): ?>\n                <span class=\"fixed-model\"><?= htmlspecialchars($meta['fixed_model']) ?><\/span>\n                <?php elseif ($currentModel !== null || $usesVision || $usesLlm): ?>\n                <?php\n                    $selected = $currentModel ?? ($usesVision ? \\Infrastructure\\AI\\ModelConfig::getDefaultVisionModel() : \\Infrastructure\\AI\\ModelConfig::getDefaultModel());\n                    $availableModels = $usesVision ? \\Infrastructure\\AI\\ModelConfig::getVisionModels() : \\Infrastructure\\AI\\ModelConfig::getAll();\n                    $ollamaModels = array_filter($availableModels, fn ($k) => str_starts_with($k, 'ollama:'), ARRAY_FILTER_USE_KEY);\n                    $anthropicModels = array_filter($availableModels, fn ($k) => !str_starts_with($k, 'ollama:'), ARRAY_FILTER_USE_KEY);\n                ?>\n                <select name=\"model\" class=\"form-select form-select--compact\"\n                        hx-post=\"\/content-pipeline\/<?= $pipeline['id'] ?>\/steps\/<?= $step['id'] ?>\/model\"\n                        hx-headers='{\"X-CSRF-TOKEN\": \"<?= $csrfToken ?>\"}'\n                        hx-swap=\"none\"\n                        hx-disabled-elt=\"this\"\n                        hx-on::after-request=\"this.classList.toggle('is-saved', event.detail.successful); setTimeout(() => this.classList.remove('is-saved'), 1000)\">\n                    <?php if (!empty($ollamaModels)): ?>\n                    <optgroup label=\"Ollama (lokal)\">\n                        <?php foreach ($ollamaModels as $modelId => $label): ?>\n                        <option value=\"<?= htmlspecialchars($modelId) ?>\" <?= $selected === $modelId ? 'selected' : '' ?>><?= htmlspecialchars($label) ?><\/option>\n                        <?php endforeach; ?>\n                    <\/optgroup>\n                    <?php endif; ?>\n                    <?php if (!empty($anthropicModels)): ?>\n                    <optgroup label=\"Anthropic\">\n                        <?php foreach ($anthropicModels as $modelId => $label): ?>\n                        <option value=\"<?= htmlspecialchars($modelId) ?>\" <?= $selected === $modelId ? 'selected' : '' ?>><?= htmlspecialchars($label) ?><\/option>\n                        <?php endforeach; ?>\n                    <\/optgroup>\n                    <?php endif; ?>\n                <\/select>\n                <?php else: ?>\n                <span class=\"text-muted\">-<\/span>\n                <?php endif; ?>\n            <\/td>\n            <td class=\"storage-cell\">\n                <?php if (!empty($meta['has_collection'])): ?>\n                <span class=\"storage-prefix\">Qdrant:<\/span>\n                <select name=\"collection\" class=\"collection-select\"\n                        hx-post=\"\/content-pipeline\/<?= $pipeline['id'] ?>\/steps\/<?= $step['id'] ?>\/collection\"\n                        hx-headers='{\"X-CSRF-TOKEN\": \"<?= $csrfToken ?>\"}'\n                        hx-swap=\"none\"\n                        hx-disabled-elt=\"this\"\n                        hx-on::after-request=\"this.classList.toggle('is-saved', event.detail.successful); setTimeout(() => this.classList.remove('is-saved'), 1000)\">\n                    <?php foreach ($collections as $collKey => $collLabel): ?>\n                    <option value=\"<?= htmlspecialchars($collKey) ?>\" <?= ($config['collection'] ?? 'documents') === $collKey ? 'selected' : '' ?>>\n                        <?= htmlspecialchars($collKey) ?>\n                    <\/option>\n                    <?php endforeach; ?>\n                <\/select>\n                <?php elseif ($storage): ?>\n                <code class=\"storage-code\"><?= htmlspecialchars($storage) ?><\/code>\n                <?php else: ?>\n                <span class=\"text-muted\">-<\/span>\n                <?php endif; ?>\n            <\/td>\n            <td>\n                <?php if ($displayConfig): ?>\n                <code class=\"config-code\"><?= htmlspecialchars(json_encode($displayConfig, JSON_UNESCAPED_UNICODE)) ?><\/code>\n                <?php else: ?>\n                <span class=\"text-muted\">-<\/span>\n                <?php endif; ?>\n            <\/td>\n        <\/tr>\n        <?php endforeach; ?>\n    <\/tbody>\n<\/table>\n\n<h2>Ausführungen<\/h2>\n\n<?php if (!empty($runs)): ?>\n<table>\n    <thead>\n        <tr>\n            <th>ID<\/th>\n            <th>Status<\/th>\n            <th>Gestartet<\/th>\n            <th>Beendet<\/th>\n            <th>Dokumente<\/th>\n            <th>Chunks<\/th>\n        <\/tr>\n    <\/thead>\n    <tbody>\n        <?php foreach ($runs as $run): ?>\n        <tr>\n            <td><a href=\"\/content-pipeline\/<?= $pipeline['id'] ?>\/run\/<?= $run['id'] ?>\/status\">#<?= $run['id'] ?><\/a><\/td>\n            <td>\n                <span class=\"badge badge--<?= $run['status'] === 'completed' ? 'success' : ($run['status'] === 'failed' ? 'danger' : ($run['status'] === 'running' ? 'warning' : 'muted')) ?>\">\n                    <?= $run['status'] ?>\n                <\/span>\n            <\/td>\n            <td><?= $run['started_at'] ?? '-' ?><\/td>\n            <td><?= $run['completed_at'] ?? '-' ?><\/td>\n            <td>\n                <?= $run['documents_processed'] ?? 0 ?>\/<?= $run['documents_total'] ?? 0 ?>\n                <?php if (($run['documents_failed'] ?? 0) > 0): ?>\n                <span class=\"text-danger\">(<?= $run['documents_failed'] ?> Fehler)<\/span>\n                <?php endif; ?>\n            <\/td>\n            <td><?= $run['chunks_created'] ?? 0 ?><\/td>\n        <\/tr>\n        <?php endforeach; ?>\n    <\/tbody>\n<\/table>\n<?php else: ?>\n<p class=\"empty-state empty-state--small\">Noch keine Ausführungen vorhanden.<\/p>\n<?php endif; ?>\n\n<p class=\"links-bar\">\n    <a href=\"\/content-pipeline\">Zurück zur Übersicht<\/a>\n<\/p>\n\n<style>\n.config-list {\n    list-style: none;\n    padding: 0;\n    margin: 1rem 0 2rem;\n}\n.config-list__item {\n    display: flex;\n    align-items: center;\n    gap: 0.5rem;\n    padding: 0.5rem 0;\n    border-bottom: 1px solid var(--border-color-light, #eee);\n}\n.config-list__label {\n    font-weight: 500;\n    min-width: 100px;\n}\n.config-list__input {\n    flex: 1;\n    font-family: monospace;\n    f... [TRUNCATED-7f4773946b6bad3f]",
        "structuredPatch": [
            {
                "oldStart": 309,
                "oldLines": 149,
                "newStart": 309,
                "newLines": 5,
                "lines": [
                    " }",
                    " <\/style>",
                    " ",
                    "-<script>",
                    "-document.addEventListener('DOMContentLoaded', function() {",
                    "-    const pipelineId = <?= (int) $pipeline['id'] ?>;",
                    "-",
                    "-    \/\/ Model-Dropdowns",
                    "-    document.querySelectorAll('.model-cell select').forEach(select => {",
                    "-        select.addEventListener('change', async function() {",
                    "-            const row = this.closest('tr');",
                    "-            const stepId = row.dataset.stepId;",
                    "-            const model = this.value;",
                    "-",
                    "-            this.classList.add('is-saving');",
                    "-",
                    "-            try {",
                    "-                const response = await fetch(`\/content-pipeline\/${pipelineId}\/steps\/${stepId}\/model`, {",
                    "-                    method: 'POST',",
                    "-                    headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },",
                    "-                    body: 'model=' + encodeURIComponent(model)",
                    "-                });",
                    "-",
                    "-                const data = await response.json();",
                    "-",
                    "-                if (data.success) {",
                    "-                    this.classList.remove('is-saving');",
                    "-                    this.classList.add('is-saved');",
                    "-                    setTimeout(() => this.classList.remove('is-saved'), 500);",
                    "-",
                    "-                    \/\/ Speichere in localStorage für User-Präferenz",
                    "-                    localStorage.setItem('pipeline_default_model', model);",
                    "-                } else {",
                    "-                    alert('Fehler: ' + (data.error || 'Unbekannter Fehler'));",
                    "-                    this.classList.remove('is-saving');",
                    "-                }",
                    "-            } catch (error) {",
                    "-                alert('Speichern fehlgeschlagen: ' + error.message);",
                    "-                this.classList.remove('is-saving');",
                    "-            }",
                    "-        });",
                    "-    });",
                    "-",
                    "-    \/\/ User-Präferenz für neues Standard-Modell laden",
                    "-    const savedModel = localStorage.getItem('pipeline_default_model');",
                    "-    if (savedModel) {",
                    "-        console.log('Gespeichertes Standard-Modell:', savedModel);",
                    "-    }",
                    "-",
                    "-    \/\/ Collection-Dropdowns",
                    "-    document.querySelectorAll('.collection-select').forEach(select => {",
                    "-        select.addEventListener('change', async function() {",
                    "-            const stepId = this.dataset.stepId;",
                    "-            const collection = this.value;",
                    "-",
                    "-            this.classList.add('is-saving');",
                    "-",
                    "-            try {",
                    "-                const response = await fetch(`\/content-pipeline\/${pipelineId}\/steps\/${stepId}\/collection`, {",
                    "-                    method: 'POST',",
                    "-                    headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },",
                    "-                    body: 'collection=' + encodeURIComponent(collection)",
                    "-                });",
                    "-",
                    "-                const data = await response.json();",
                    "-",
                    "-                if (data.success) {",
                    "-                    this.classList.remove('is-saving');",
                    "-                    this.classList.add('is-saved');",
                    "-                    setTimeout(() => this.classList.remove('is-saved'), 500);",
                    "-                } else {",
                    "-                    alert('Fehler: ' + (data.error || 'Unbekannter Fehler'));",
                    "-                    this.classList.remove('is-saving');",
                    "-                }",
                    "-            } catch (error) {",
                    "-                alert('Speichern fehlgeschlagen: ' + error.message);",
                    "-                this.classList.remove('is-saving');",
                    "-            }",
                    "-        });",
                    "-    });",
                    "-",
                    "-    \/\/ Inline-Edit für Quelle und Dateitypen",
                    "-    document.querySelectorAll('.config-list__value.editable').forEach(el => {",
                    "-        el.addEventListener('click', function() {",
                    "-            if (this.querySelector('input')) return;",
                    "-",
                    "-            const field = this.dataset.field;",
                    "-            const currentValue = this.textContent.trim();",
                    "-            const originalEl = this;",
                    "-",
                    "-            const input = document.createElement('input');",
                    "-            input.type = 'text';",
                    "-            input.className = 'config-list__input';",
                    "-            input.value = currentValue;",
                    "-",
                    "-            originalEl.textContent = '';",
                    "-            originalEl.appendChild(input);",
                    "-            input.focus();",
                    "-            input.select();",
                    "-",
                    "-            async function saveValue() {",
                    "-                const newValue = input.value.trim();",
                    "-                if (newValue === currentValue) {",
                    "-                    originalEl.textContent = currentValue;",
                    "-                    return;",
                    "-                }",
                    "-",
                    "-                originalEl.classList.add('is-saving');",
                    "-",
                    "-                try {",
                    "-                    const response = await fetch(`\/content-pipeline\/${pipelineId}\/config`, {",
                    "-                        method: 'POST',",
                    "-                        headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },",
                    "-                        body: field + '=' + encodeURIComponent(newValue)",
                    "-                    });",
                    "-",
                    "-                    const data = await response.json();",
                    "-",
                    "-                    if (data.success) {",
                    "-                        originalEl.textContent = newValue;",
                    "-                        originalEl.classList.remove('is-saving');",
                    "-                    } else {",
                    "-                        alert('Fehler: ' + (data.error || 'Unbekannter Fehler'));",
                    "-                        originalEl.textContent = currentValue;",
                    "-                        originalEl.classList.remove('is-saving');",
                    "-                    }",
                    "-                } catch (error) {",
                    "-                    alert('Speichern fehlgeschlagen: ' + error.message);",
                    "-                    originalEl.textContent = currentValue;",
                    "-                    originalEl.classList.remove('is-saving');",
                    "-                }",
                    "-            }",
                    "-",
                    "-            input.addEventListener('blur', saveValue);",
                    "-            input.addEventListener('keydown', function(e) {",
                    "-                if (e.key === 'Enter') {",
                    "-                    e.preventDefault();",
                    "-                    input.blur();",
                    "-                } else if (e.key === 'Escape') {",
                    "-                    originalEl.textContent = currentValue;",
                    "-                }",
                    "-            });",
                    "-        });",
                    "-    });",
                    "-});",
                    "-<\/script>",
                    "-",
                    " <?php $content = ob_get_clean(); ?>",
                    " <?php require VIEW_PATH . '\/layout.php'; ?>"
                ]
            }
        ],
        "userModified": false,
        "replaceAll": false
    }
}
← Vorheriger Zur Liste Nächster →