This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## 1.8.2 - 2026-07-23
|
||||
|
||||
- Fixed the Bulk results view so it previews the same accessible badge-plus-visible-text disclosure used by the recommended `embedHtml` export.
|
||||
- Renamed the raw badge link to `SVG (nur Grafik)` to make clear that the standalone SVG is only the visual asset and not the recommended first-exposure integration.
|
||||
- Kept Bulk HTML exports unchanged on `embedHtml`; this release fixes the misleading preview/link presentation rather than introducing a second rendering path.
|
||||
|
||||
## 1.8.1 - 2026-07-23
|
||||
|
||||
- Added an accessible first-exposure embed with visible link text next to the SVG badge instead of relying on SVG/`alt` information alone.
|
||||
|
||||
@@ -28,7 +28,7 @@ build-bulk:
|
||||
CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o bin/ai-disclosure-bulk ./cmd/bulk
|
||||
|
||||
docker-build:
|
||||
docker build -t ai-disclosure-standard:1.8.1-local .
|
||||
docker build -t ai-disclosure-standard:1.8.2-local .
|
||||
|
||||
docker-build-bulk:
|
||||
docker build -f Dockerfile.bulk -t ai-disclosure-bulk:1.0.0-local .
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# AI Disclosure Standard 1.8.1
|
||||
# AI Disclosure Standard 1.8.2
|
||||
|
||||
Ein zustandsloser Go-Dienst für sichtbare und maschinenlesbare Erklärungen zur KI-Nutzung in Artikeln, Webseiten und einzelnen Inhaltsbestandteilen.
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
+28
-2
@@ -311,6 +311,30 @@
|
||||
return {html, markdown, json, jsonl, csv};
|
||||
}
|
||||
|
||||
function buildDisclosurePreview(data) {
|
||||
const wrap = document.createElement('p');
|
||||
wrap.className = 'bulk-disclosure-preview';
|
||||
const link = document.createElement('a');
|
||||
link.className = 'bulk-disclosure-preview__link';
|
||||
link.href = data.declarationUrl;
|
||||
link.target = '_blank';
|
||||
link.rel = 'noopener';
|
||||
|
||||
const badge = document.createElement('img');
|
||||
badge.className = 'bulk-disclosure-preview__badge';
|
||||
badge.src = data.badgeUrl;
|
||||
badge.alt = '';
|
||||
badge.setAttribute('aria-hidden', 'true');
|
||||
|
||||
const text = document.createElement('span');
|
||||
text.className = 'bulk-disclosure-preview__text';
|
||||
text.textContent = data.accessibleText || 'KI-Nutzung – Details zur Kennzeichnung';
|
||||
|
||||
link.append(badge, text);
|
||||
wrap.appendChild(link);
|
||||
return wrap;
|
||||
}
|
||||
|
||||
function renderResults(results) {
|
||||
currentResults = results;
|
||||
exportsCache = buildExports(results);
|
||||
@@ -326,14 +350,16 @@
|
||||
const code = document.createElement('code');
|
||||
code.textContent = item.subject;
|
||||
subjectCell.appendChild(code);
|
||||
const previewCell = document.createElement('td');
|
||||
const statusCell = document.createElement('td');
|
||||
statusCell.className = item.ok ? 'ok' : 'failed';
|
||||
statusCell.textContent = item.ok ? '✓ erzeugt' : `Fehler: ${item.error || 'unbekannt'}`;
|
||||
const linksCell = document.createElement('td');
|
||||
if (item.ok && item.data) {
|
||||
previewCell.appendChild(buildDisclosurePreview(item.data));
|
||||
const links = document.createElement('div');
|
||||
links.className = 'result-links';
|
||||
[['Declaration', item.data.declarationUrl], ['JSON-LD', item.data.manifestUrl], ['Badge', item.data.badgeUrl]].forEach(([label, href]) => {
|
||||
[['Declaration', item.data.declarationUrl], ['JSON-LD', item.data.manifestUrl], ['SVG (nur Grafik)', item.data.badgeUrl]].forEach(([label, href]) => {
|
||||
const a = document.createElement('a');
|
||||
a.textContent = label;
|
||||
a.href = href;
|
||||
@@ -343,7 +369,7 @@
|
||||
});
|
||||
linksCell.appendChild(links);
|
||||
}
|
||||
tr.append(subjectCell, statusCell, linksCell);
|
||||
tr.append(subjectCell, previewCell, statusCell, linksCell);
|
||||
tbody.appendChild(tr);
|
||||
});
|
||||
$('output-html').value = exportsCache.html;
|
||||
|
||||
@@ -211,11 +211,11 @@
|
||||
<button type="button" class="button secondary" data-download="csv">CSV herunterladen</button>
|
||||
</div>
|
||||
|
||||
<p class="embed-note">Der HTML-Export ist die empfohlene Ein-Schritt-Integration: sichtbarer, tastaturerreichbarer Hinweis mit Text neben dem Badge plus eingebettetes JSON-LD. Das SVG ist dabei dekorativ; die zugängliche Bezeichnung stammt aus dem sichtbaren Linktext.</p>
|
||||
<p class="embed-note">Der HTML-Export ist die empfohlene Ein-Schritt-Integration: sichtbarer, tastaturerreichbarer Hinweis mit Text neben dem Badge plus eingebettetes JSON-LD. Die Vorschau unten zeigt genau diese sichtbare Kennzeichnung. Der Link „SVG (nur Grafik)“ dient nur zum separaten Abruf der Bilddatei und ist nicht die empfohlene alleinstehende Integration.</p>
|
||||
|
||||
<div class="result-table-wrap">
|
||||
<table class="result-table">
|
||||
<thead><tr><th>Inhalt</th><th>Status</th><th>Links</th></tr></thead>
|
||||
<thead><tr><th>Inhalt</th><th>Kennzeichnung</th><th>Status</th><th>Links</th></tr></thead>
|
||||
<tbody id="result-rows"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -25,7 +25,7 @@ spec:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: app
|
||||
image: ghcr.io/REPLACE_ME/ai-disclosure-standard:1.8.1
|
||||
image: ghcr.io/REPLACE_ME/ai-disclosure-standard:1.8.2
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- name: http
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
version: "3.9"
|
||||
services:
|
||||
app:
|
||||
image: ghcr.io/REPLACE_ME/ai-disclosure-standard:1.8.1
|
||||
image: ghcr.io/REPLACE_ME/ai-disclosure-standard:1.8.2
|
||||
environment:
|
||||
BASE_URL: https://ai.example.org
|
||||
PUBLIC_NAME: AI Usage Disclosure
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Mehrsprachige Hintergrundseite
|
||||
|
||||
Version 1.8.1 stellt unter `/background` eine eigenständige Informationsseite zur KI-Kennzeichnung und zu Artikel 50 des EU AI Act bereit.
|
||||
Version 1.8.2 stellt unter `/background` eine eigenständige Informationsseite zur KI-Kennzeichnung und zu Artikel 50 des EU AI Act bereit.
|
||||
|
||||
## Routen
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ Initialization is performed in `internal/app/server.go`. The product ID and embe
|
||||
```go
|
||||
licenses := licenseclient.New(ctx, licenseclient.Config{
|
||||
Product: "ai-disclosure-standard",
|
||||
ClientVersion: "1.8.1",
|
||||
ClientVersion: "1.8.2",
|
||||
Token: cfg.LicenseToken,
|
||||
TrustStore: trustStore,
|
||||
BaseURL: cfg.BaseURL,
|
||||
|
||||
@@ -119,7 +119,7 @@ Anfrage:
|
||||
"baseUrl": "https://ai.example.org",
|
||||
"host": "ai.example.org",
|
||||
"instanceId": "production-eu-1",
|
||||
"clientVersion": "1.8.1"
|
||||
"clientVersion": "1.8.2"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
const (
|
||||
ProductID = "ai-disclosure-standard"
|
||||
ProductVersion = "1.8.1"
|
||||
ProductVersion = "1.8.2"
|
||||
FeatureCustomText = "custom_text"
|
||||
FeatureCustomBadge = "custom_badge"
|
||||
FeatureWhiteLabel = "white_label"
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
bulkweb "github.com/b1tsblog/ai-disclosure-standard/bulkweb"
|
||||
)
|
||||
|
||||
const Version = "1.0.1"
|
||||
const Version = "1.0.2"
|
||||
|
||||
type Server struct {
|
||||
cfg Config
|
||||
|
||||
@@ -123,3 +123,37 @@ func TestRenderBatchHonoursConfiguredLimit(t *testing.T) {
|
||||
t.Fatalf("status %d: %s", w.Code, w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBulkUIUsesAccessibleDisclosurePreview(t *testing.T) {
|
||||
h, err := New(Config{
|
||||
ListenAddress: ":0", CoreInternalURL: "http://127.0.0.1:9",
|
||||
DisclosureBaseURL: "https://public.example", GeneratorURL: "https://public.example",
|
||||
PublicName: "Bulk", MaxURLs: 10, Workers: 1, RequestTimeout: time.Second,
|
||||
}, testLogger())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
indexReq := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
indexRes := httptest.NewRecorder()
|
||||
h.ServeHTTP(indexRes, indexReq)
|
||||
if indexRes.Code != http.StatusOK {
|
||||
t.Fatalf("index status %d: %s", indexRes.Code, indexRes.Body.String())
|
||||
}
|
||||
if !strings.Contains(indexRes.Body.String(), "<th>Kennzeichnung</th>") {
|
||||
t.Fatalf("bulk result table does not expose the disclosure preview column")
|
||||
}
|
||||
|
||||
jsReq := httptest.NewRequest(http.MethodGet, "/static/bulk.js", nil)
|
||||
jsRes := httptest.NewRecorder()
|
||||
h.ServeHTTP(jsRes, jsReq)
|
||||
if jsRes.Code != http.StatusOK {
|
||||
t.Fatalf("bulk.js status %d: %s", jsRes.Code, jsRes.Body.String())
|
||||
}
|
||||
body := jsRes.Body.String()
|
||||
for _, required := range []string{"buildDisclosurePreview", "accessibleText", "SVG (nur Grafik)"} {
|
||||
if !strings.Contains(body, required) {
|
||||
t.Fatalf("bulk.js missing accessible preview marker %q", required)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,13 +183,13 @@ func Build(lang, productName, baseURL, salesURL, contactURL string, prices Price
|
||||
# Adjust BASE_URL and PUBLIC_NAME in .env
|
||||
docker compose up -d --build
|
||||
curl -fsS http://localhost:8080/readyz`},
|
||||
{ID: "docker", Title: copy.InstallTitles[1], Summary: copy.InstallSummaries[1], Code: `docker build -t ai-disclosure-standard:1.8.1 .
|
||||
{ID: "docker", Title: copy.InstallTitles[1], Summary: copy.InstallSummaries[1], Code: `docker build -t ai-disclosure-standard:1.8.2 .
|
||||
docker run -d --name ai-disclosure \
|
||||
-p 8080:8080 \
|
||||
-e BASE_URL=https://ai.example.org \
|
||||
-e PUBLIC_NAME="AI Usage Disclosure" \
|
||||
--read-only --tmpfs /tmp \
|
||||
ai-disclosure-standard:1.8.1`},
|
||||
ai-disclosure-standard:1.8.2`},
|
||||
{ID: "kubernetes", Title: copy.InstallTitles[2], Summary: copy.InstallSummaries[2], Code: `# Image, Domain und TLS-Secret in deploy/kubernetes.yaml ersetzen
|
||||
kubectl create secret generic ai-disclosure-license \
|
||||
--from-literal=token='...'
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
title: AI Usage Disclosure API
|
||||
version: 1.8.1
|
||||
version: 1.8.2
|
||||
description: Stateless multilingual badge, declaration and validation API with optional licensed presentation capabilities.
|
||||
servers:
|
||||
- url: https://ai.example.org
|
||||
|
||||
@@ -158,7 +158,7 @@
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer><span>{{.Background.Footer}} · App 1.8.1 · Schema 1.3 · {{.License.Edition}}</span>{{template "legal-links" .}}</footer>
|
||||
<footer><span>{{.Background.Footer}} · App 1.8.2 · Schema 1.3 · {{.License.Edition}}</span>{{template "legal-links" .}}</footer>
|
||||
<script src="/static/marketing.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -290,7 +290,7 @@
|
||||
<article><p class="eyebrow">HA</p><h2>{{index .Text "api_stateless_title"}}</h2><p>{{index .Text "api_stateless_desc"}}</p></article>
|
||||
</section>
|
||||
</main>
|
||||
<footer><span>AI Usage Disclosure · App 1.8.1 · Schema 1.3 · {{.License.Edition}}</span>{{template "legal-links" .}}</footer>
|
||||
<footer><span>AI Usage Disclosure · App 1.8.2 · Schema 1.3 · {{.License.Edition}}</span>{{template "legal-links" .}}</footer>
|
||||
<script nonce="{{.CSPNonce}}">window.APP_CONFIG={{.AppConfig}};</script>
|
||||
<script src="/static/app.js" defer></script>
|
||||
</body>
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer><span>{{.Marketing.Footer}} · App 1.8.1 · Schema 1.3 · {{.License.Edition}}</span>{{template "legal-links" .}}</footer>
|
||||
<footer><span>{{.Marketing.Footer}} · App 1.8.2 · Schema 1.3 · {{.License.Edition}}</span>{{template "legal-links" .}}</footer>
|
||||
<script src="/static/marketing.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user