Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# next version

- Link the UCP settings to their documentation. The Exposure sub-tab of the Agentic Commerce tab now carries a link below the capability and transport checkboxes that opens the UCP section of the user documentation in a new tab, in the language of the administration. Until now the tab explained each option only in a one-line tooltip and gave no way to read on.
- Let an extension register its own UCP OAuth scope. The supported scopes were a private class constant, so a plugin that adds a UCP capability of its own had no way to make its scope grantable: the token request threw `Unsupported OAuth scope`, and a consent flow that swallowed the error burned its one-time handle and told the buyer the authorization link had expired. Tag a scope provider with `swag_agentic_commerce.ucp.oauth_scope_provider` and its scope is advertised in `scopes_supported` on `/.well-known/oauth-authorization-server` and accepted in an authorization request. A request that omits the scope still gets only the three built-in ones; an extension scope has to be asked for by name. An unregistered scope is still rejected -- now with the supported set named in the message, which is what made this hard to diagnose.
- Require Shopware `6.5.8` or newer. `6.5.0.0` through `6.5.7.4` were listed as compatible but could never install: those versions ship Symfony 6.3, while both the extension's own routes and the UCP SDK need Symfony 6.4. Installation therefore ended in a Composer error about `symfony/config` that a merchant cannot act on. Such a shop now sees the extension as incompatible; updating to `6.5.8.x` fixes that and stays inside the same minor.
- Let Shopware install the UCP SDK instead of shipping it inside the archive. 1.3.0 put the SDK in the plugin's own `vendor/` and loaded the autoloader Composer had generated for it, because Shopware does not load a plugin's `vendor/autoload.php` by itself. Every shop that installed it then carried two separate package registries: FroshTools reported `2 autoloaders registered`, and a question as ordinary as which version of a package is installed could be answered from the plugin's copy instead of the shop's. The extension now carries no dependencies at all. It has Shopware run `composer require` on install and update instead, which is what that mechanism is there for on a zip-installed extension: the extension itself resolves from the `custom/plugins/*` path repository every Shopware project declares, and the SDK version it names comes from Packagist into the shop's own `vendor/`. Nothing changes for a shop that installs through Composer. What is new is that installing has to reach Packagist -- without it the install stops with a Composer error, rather than leaving an extension that cannot run.
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG_de-DE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# next version

- Die UCP-Einstellungen verweisen jetzt auf ihre Dokumentation. Im Unterreiter „Bereitstellung“ des Tabs „Agentic Commerce“ steht unterhalb der Checkboxen für Funktionen und Transportwege ein Link, der den UCP-Abschnitt der Benutzerdokumentation in der Sprache der Administration in einem neuen Tab öffnet. Bisher erklärte der Tab jede Option nur in einem einzeiligen Tooltip und bot keine Möglichkeit, weiterzulesen.
- Erweiterungen können jetzt eigene UCP-OAuth-Scopes registrieren. Bisher war die Liste der zulässigen Scopes fest im Code hinterlegt, sodass ein Plugin mit eigener UCP-Capability seinen Scope nicht freischalten konnte: Die Token-Anfrage schlug mit `Unsupported OAuth scope` fehl. Weil das Plugin diesen Fehler still abfing, der Autorisierungslink aber schon eingelöst war, sah der Käufer nur die Meldung, der Link sei abgelaufen. Jetzt genügt ein Scope-Provider mit dem Service-Tag `swag_agentic_commerce.ucp.oauth_scope_provider`: Sein Scope wird in `scopes_supported` unter `/.well-known/oauth-authorization-server` veröffentlicht und in Autorisierungsanfragen akzeptiert. Ein Client, der keinen Scope angibt, erhält wie bisher nur die drei eingebauten Scopes; den Scope einer Erweiterung muss er ausdrücklich anfordern. Nicht registrierte Scopes werden weiterhin abgelehnt, die Fehlermeldung führt jetzt aber alle unterstützten Scopes auf -- genau diese Angabe fehlte bei der Fehlersuche.
- Die Erweiterung setzt jetzt Shopware `6.5.8` oder neuer voraus. `6.5.0.0` bis `6.5.7.4` wurden als kompatibel angezeigt, ließen sich aber nie installieren: Diese Versionen enthalten Symfony 6.3, während sowohl die Routen der Erweiterung als auch das UCP-SDK Symfony 6.4 benötigen. Die Installation brach deshalb mit einer Composer-Fehlermeldung zu `symfony/config` ab, mit der ein Händler nichts anfangen kann. In betroffenen Shops wird die Erweiterung jetzt als nicht kompatibel angezeigt; ein Update auf `6.5.8.x` behebt das und bleibt innerhalb derselben Minor-Version.
- Das UCP SDK wird nicht mehr mitgeliefert, sondern von Shopware installiert. 1.3.0 legte es in das plugin-eigene `vendor/` und lud den Autoloader, den Composer dafür erzeugt hatte -- denn das `vendor/autoload.php` einer Erweiterung lädt Shopware nicht von sich aus. Damit führte jeder Shop zwei getrennte Paketverzeichnisse: FroshTools meldete `2 autoloaders registered`, und die Frage, welche Version eines Pakets installiert ist, konnte aus der Kopie der Erweiterung beantwortet werden statt aus der des Shops. Die Erweiterung bringt jetzt keine Abhängigkeiten mehr mit, sondern lässt Shopware bei Installation und Update `composer require` ausführen -- dafür ist dieser Weg bei Erweiterungen aus einer ZIP-Datei gedacht. Die Erweiterung selbst wird dabei über das Pfad-Repository `custom/plugins/*` aufgelöst, das jedes Shopware-Projekt mitbringt, das festgelegte SDK kommt von Packagist in das `vendor/` des Shops. Für Shops, die über Composer installieren, ändert sich nichts. Neu ist, dass die Installation Packagist erreichen muss: Ohne Internetzugang bricht sie mit einem Composer-Fehler ab, statt eine unvollständige Erweiterung zu hinterlassen.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
"transportA2aDescription": "A2A – Agent-zu-Agent-Protokoll.",
"transportEmbeddedDescription": "Embedded – eingebettete In-Context-Oberfläche.",
"transportMcpDescription": "MCP – Model-Context-Protocol-Server.",
"docsLinkLabel": "Mehr über die UCP-Einstellungen in der Dokumentation erfahren",
"docsUrl": "https://docs.shopware.com/de/shopware-6-de/erweiterungen/agentic-commerce#ucp-universal-commerce-protocol",
"previewLabel": "Profilvorschau"
},
"openAiSettingsTitle": "OpenAI-Einstellungen",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
"transportA2aDescription": "A2A — agent-to-agent protocol.",
"transportEmbeddedDescription": "Embedded — in-context embedded surface.",
"transportMcpDescription": "MCP — Model Context Protocol server.",
"docsLinkLabel": "Learn more about the UCP settings in the documentation",
"docsUrl": "https://docs.shopware.com/en/shopware-6-en/extensions/agentic-commerce#ucp-universal-commerce-protocol",
"previewLabel": "Profile preview"
},
"openAiSettingsTitle": "OpenAI settings",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,17 @@
</div>
{% endblock %}
</div>

{% block sw_sales_channel_detail_agentic_commerce_ucp_docs_link %}
<p class="sw-sales-channel-detail-agentic-commerce__docs-hint">
<sw-external-link
class="sw-sales-channel-detail-agentic-commerce__docs-link"
:href="$t('sw-sales-channel.detail.agenticCommerce.ucp.docsUrl')"
>
{{ $t('sw-sales-channel.detail.agenticCommerce.ucp.docsLinkLabel') }}
</sw-external-link>
</p>
{% endblock %}
</div>
</template>
{% endblock %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@
}
}

// Documentation pointer directly under the capability/transport lists —
// the option grid already carries the 12px gap above it.
&__docs-hint {
margin: 0;
}

// Signing keys rendered as a lightweight table: aligned columns (key id /
// algorithm / status / actions) so the action buttons never shift with the
// key-name length, and the actions column pins to the right. The Create key
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,17 @@
</div>
</div>
</div>

{% block sw_sales_channel_detail_agentic_commerce_ucp_docs_link %}
<p class="sw-sales-channel-detail-agentic-commerce__docs-hint">
<sw-external-link
class="sw-sales-channel-detail-agentic-commerce__docs-link"
:href="$t('sw-sales-channel.detail.agenticCommerce.ucp.docsUrl')"
>
{{ $t('sw-sales-channel.detail.agenticCommerce.ucp.docsLinkLabel') }}
</sw-external-link>
</p>
{% endblock %}
</div>
</sw-card>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* @sw-package discovery
*
* The Exposure sub-tab links the capability/transport checkboxes to the user
* documentation. The link is snippet-driven so each admin locale points at its
* own docs page; both the Meteor (6.6+) and the legacy (6.5) template must
* render it, and both locales must resolve to the UCP section of the
* Agentic Commerce user docs.
*/
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';

const VIEW_DIR = resolve(
__dirname,
'../../../../../src/extension/sw-sales-channel/view/sw-sales-channel-detail-agentic-commerce',
);
const SNIPPET_DIR = resolve(__dirname, '../../../../../src/extension/sw-sales-channel/snippet');

const DOCS_URL_KEY = 'sw-sales-channel.detail.agenticCommerce.ucp.docsUrl';
const DOCS_LABEL_KEY = 'sw-sales-channel.detail.agenticCommerce.ucp.docsLinkLabel';

function readSnippets(locale) {
return JSON.parse(readFileSync(resolve(SNIPPET_DIR, `${locale}.json`), 'utf8'));
}

describe('sw-sales-channel-detail-agentic-commerce docs link', () => {
it.each([
['sw-sales-channel-detail-agentic-commerce.mt.html.twig'],
['sw-sales-channel-detail-agentic-commerce.sw.html.twig'],
])('%s renders the docs link below the option grid', (templateFile) => {
const template = readFileSync(resolve(VIEW_DIR, templateFile), 'utf8');

const optionGridIndex = template.indexOf('sw-sales-channel-detail-agentic-commerce__option-grid');
const docsLinkIndex = template.indexOf('sw-sales-channel-detail-agentic-commerce__docs-link');

expect(optionGridIndex).toBeGreaterThan(-1);
expect(docsLinkIndex).toBeGreaterThan(optionGridIndex);
expect(template).toContain(`:href="$t('${DOCS_URL_KEY}')"`);
expect(template).toContain(`$t('${DOCS_LABEL_KEY}')`);
});

it.each([
['en', 'https://docs.shopware.com/en/shopware-6-en/extensions/agentic-commerce#ucp-universal-commerce-protocol'],
['de', 'https://docs.shopware.com/de/shopware-6-de/erweiterungen/agentic-commerce#ucp-universal-commerce-protocol'],
])('the %s snippets point at the UCP section of the user docs', (locale, expectedUrl) => {
const ucp = readSnippets(locale)['sw-sales-channel'].detail.agenticCommerce.ucp;

expect(ucp.docsUrl).toBe(expectedUrl);
expect(ucp.docsLinkLabel.trim()).not.toBe('');
});
});
7 changes: 7 additions & 0 deletions tests/e2e/admin/ucp-sales-channel-tab.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ test.describe('UCP sales-channel admin tab', () => {
await expect(tabRoot.getByText(transport, { exact: true })).toBeVisible();
}

const docsLink = tabRoot.locator('.sw-sales-channel-detail-agentic-commerce__docs-link').first();
await expect(docsLink).toBeVisible();
await expect(docsLink).toHaveAttribute(
'href',
/^https:\/\/docs\.shopware\.com\/.+\/agentic-commerce#ucp-universal-commerce-protocol$/,
);

const previewTab = tabRoot.getByText('Preview', { exact: true });
if (await previewTab.isVisible().catch(() => false)) {
await previewTab.click();
Expand Down
Loading