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
2 changes: 1 addition & 1 deletion .github/workflows/deploy_pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ jobs:

- name: Build Production Shell & Catalogs with Correct Base URLs
run: |
yarn workspace a2ui-composer-shell run build --base-href=/composer/
yarn workspace ng-basic-catalog run build --base-href=/composer/samples/ng-basic-catalog/
yarn workspace a2ui-composer-shell run build --base-href=/composer/
yarn workspace lit-basic-catalog run build --base=/composer/samples/lit-basic-catalog/
yarn workspace react-basic-catalog run build --base=/composer/samples/react-basic-catalog/

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy_pr_preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ jobs:
env:
PR_NUM: ${{ github.event.pull_request.number }}
run: |
yarn workspace a2ui-composer-shell run build --base-href=/composer/pr/${PR_NUM}/
yarn workspace ng-basic-catalog run build --base-href=/composer/pr/${PR_NUM}/samples/ng-basic-catalog/
yarn workspace a2ui-composer-shell run build --base-href=/composer/pr/${PR_NUM}/
yarn workspace lit-basic-catalog run build --base=/composer/pr/${PR_NUM}/samples/lit-basic-catalog/
yarn workspace react-basic-catalog run build --base=/composer/pr/${PR_NUM}/samples/react-basic-catalog/

Expand Down
30 changes: 15 additions & 15 deletions bridge/src/preview-bridge.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ describe('PreviewBridge Core API Runtime', () => {

await new Promise(resolve => setTimeout(resolve, 10));

expect(window.fetch).toHaveBeenCalledWith('/catalog', expect.any(Object));
expect(window.fetch).toHaveBeenCalledWith('catalog', expect.any(Object));
expect(spy).toHaveBeenCalledWith(
{
type: PreviewBridgeMessageType.A2UI_CATALOG,
Expand Down Expand Up @@ -236,8 +236,8 @@ describe('PreviewBridge Core API Runtime', () => {

await new Promise(resolve => setTimeout(resolve, 10));

expect(window.fetch).toHaveBeenNthCalledWith(1, '/catalog', expect.any(Object));
expect(window.fetch).toHaveBeenNthCalledWith(2, '/catalog.json', expect.any(Object));
expect(window.fetch).toHaveBeenNthCalledWith(1, 'catalog', expect.any(Object));
expect(window.fetch).toHaveBeenNthCalledWith(2, 'catalog.json', expect.any(Object));
expect(spy).toHaveBeenCalledWith(
{
type: PreviewBridgeMessageType.A2UI_CATALOG,
Expand Down Expand Up @@ -270,15 +270,15 @@ describe('PreviewBridge Core API Runtime', () => {

await new Promise(resolve => setTimeout(resolve, 10));

expect(window.fetch).toHaveBeenNthCalledWith(1, '/catalog', expect.any(Object));
expect(window.fetch).toHaveBeenNthCalledWith(2, '/catalog.json', expect.any(Object));
expect(window.fetch).toHaveBeenNthCalledWith(1, 'catalog', expect.any(Object));
expect(window.fetch).toHaveBeenNthCalledWith(2, 'catalog.json', expect.any(Object));
expect(spy).toHaveBeenCalledWith(
{
type: PreviewBridgeMessageType.A2UI_CATALOG,
payload: {
error: {
message:
'Catalog fetch returned HTML (SPA fallback) for both /catalog and /catalog.json. Ensure the catalog JSON is correctly hosted and served.',
'Catalog fetch returned HTML (SPA fallback) for both catalog and catalog.json. Ensure the catalog JSON is correctly hosted and served.',
},
},
},
Expand Down Expand Up @@ -310,8 +310,8 @@ describe('PreviewBridge Core API Runtime', () => {

await new Promise(resolve => setTimeout(resolve, 10));

expect(window.fetch).toHaveBeenNthCalledWith(1, '/catalog', expect.any(Object));
expect(window.fetch).toHaveBeenNthCalledWith(2, '/catalog.json', expect.any(Object));
expect(window.fetch).toHaveBeenNthCalledWith(1, 'catalog', expect.any(Object));
expect(window.fetch).toHaveBeenNthCalledWith(2, 'catalog.json', expect.any(Object));
expect(spy).toHaveBeenCalledWith(
{
type: PreviewBridgeMessageType.A2UI_CATALOG,
Expand Down Expand Up @@ -502,7 +502,7 @@ describe('PreviewBridge Core API Runtime', () => {

await new Promise(resolve => setTimeout(resolve, 10));

expect(window.fetch).toHaveBeenCalledWith('/catalog', expect.any(Object));
expect(window.fetch).toHaveBeenCalledWith('catalog', expect.any(Object));
expect(spy).toHaveBeenCalledWith(
{
type: PreviewBridgeMessageType.A2UI_CATALOG,
Expand Down Expand Up @@ -536,8 +536,8 @@ describe('PreviewBridge Core API Runtime', () => {

await new Promise(resolve => setTimeout(resolve, 10));

expect(window.fetch).toHaveBeenNthCalledWith(1, '/catalog', expect.any(Object));
expect(window.fetch).toHaveBeenNthCalledWith(2, '/catalog.json', expect.any(Object));
expect(window.fetch).toHaveBeenNthCalledWith(1, 'catalog', expect.any(Object));
expect(window.fetch).toHaveBeenNthCalledWith(2, 'catalog.json', expect.any(Object));
expect(spy).toHaveBeenCalledWith(
{
type: PreviewBridgeMessageType.A2UI_CATALOG,
Expand Down Expand Up @@ -1443,15 +1443,15 @@ describe('PreviewBridge Core API Runtime', () => {

await new Promise(resolve => setTimeout(resolve, 10));

expect(window.fetch).toHaveBeenNthCalledWith(1, '/catalog', expect.any(Object));
expect(window.fetch).toHaveBeenNthCalledWith(2, '/catalog.json', expect.any(Object));
expect(window.fetch).toHaveBeenNthCalledWith(1, 'catalog', expect.any(Object));
expect(window.fetch).toHaveBeenNthCalledWith(2, 'catalog.json', expect.any(Object));
expect(spy).toHaveBeenCalledWith(
{
type: PreviewBridgeMessageType.A2UI_CATALOG,
payload: {
error: {
message:
'Catalog fetch returned HTML and fallback to /catalog.json failed with status: 404',
'Catalog fetch returned HTML and fallback to catalog.json failed with status: 404',
},
},
},
Expand Down Expand Up @@ -1532,7 +1532,7 @@ describe('PreviewBridge Core API Runtime', () => {

await new Promise(resolve => setTimeout(resolve, 10));

expect(window.fetch).toHaveBeenCalledWith('/catalog', expect.any(Object));
expect(window.fetch).toHaveBeenCalledWith('catalog', expect.any(Object));
expect(spy).toHaveBeenCalledWith(
{
type: PreviewBridgeMessageType.A2UI_CATALOG,
Expand Down
8 changes: 4 additions & 4 deletions bridge/src/preview-bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,7 @@ export class PreviewBridge {

if (typeof window === 'undefined' || !window.fetch) return null;

let res = await this.fetchWithTimeout('/catalog');
let res = await this.fetchWithTimeout('catalog');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These URLs are now more sensitive to the way the iframe is deployed, for example, doing fetch('bar.json') yields different results when run in:

I guess this is acceptable, but it may be better to create a new URL for these resources that resolves against a more specific window.location base URL (similar to what was done below), or make a specific note about this deployment requirement in the manual of the preview bridge.

if (!res.ok) {
throw new Error(`Catalog fetch failed with status: ${res.status}`);
}
Expand All @@ -674,10 +674,10 @@ export class PreviewBridge {
const trimmedLower = rawText.trim().toLowerCase();
const isHtml = trimmedLower.startsWith('<!doctype') || trimmedLower.startsWith('<html');
if (isHtml) {
const fallbackRes = await this.fetchWithTimeout('/catalog.json');
const fallbackRes = await this.fetchWithTimeout('catalog.json');
if (!fallbackRes.ok) {
throw new Error(
`Catalog fetch returned HTML and fallback to /catalog.json failed with status: ${fallbackRes.status}`,
`Catalog fetch returned HTML and fallback to catalog.json failed with status: ${fallbackRes.status}`,
);
}
const fallbackText = await fallbackRes.text();
Expand All @@ -687,7 +687,7 @@ export class PreviewBridge {
fallbackTrimmedLower.startsWith('<html')
) {
throw new Error(
'Catalog fetch returned HTML (SPA fallback) for both /catalog and /catalog.json. Ensure the catalog JSON is correctly hosted and served.',
'Catalog fetch returned HTML (SPA fallback) for both catalog and catalog.json. Ensure the catalog JSON is correctly hosted and served.',
);
}
res = fallbackRes;
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
"bridge"
],
"scripts": {
"test": "yarn workspaces foreach -A run test",
"build": "yarn workspaces foreach -A run build",
"prettier": "yarn workspaces foreach -A run prettier",
"test": "yarn workspaces foreach -A --exclude a2ui-composer-root run test",
"build": "yarn workspaces foreach -A --topological-dev --exclude a2ui-composer-root run build",
"prettier": "yarn workspaces foreach -A --exclude a2ui-composer-root run prettier",
"tsc": "yarn --cwd shell tsc --noEmit && yarn --cwd bridge tsc --project tsconfig.bridge.json --noEmit",
"clean": "yarn workspaces foreach -A run clean",
"lint": "yarn workspaces foreach -A run lint"
"clean": "yarn workspaces foreach -A --exclude a2ui-composer-root run clean",
"lint": "yarn workspaces foreach -A --exclude a2ui-composer-root run lint"
},
"resolutions": {
"@a2ui/web_core": "0.10.2",
Expand Down
1 change: 1 addition & 0 deletions samples/ng-basic-catalog/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"polyfills": [],
"tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss",
"baseHref": "./",
"assets": [
"src/favicon.ico",
"src/assets",
Expand Down
2 changes: 1 addition & 1 deletion samples/ng-basic-catalog/src/assets/catalog.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"$id": "my_basic_catalog.json",
"title": "my_basic_catalog A2UI Catalog",
"description": "my_basic_catalog A2UI catalog, including catalog.",
"catalogId": "urn:a2ui:catalog:my_basic_catalog",
"catalogId": "https://a2ui.org/specification/v0_9/basic_catalog.json",
Comment thread
ditman marked this conversation as resolved.
"components": {
"Text": {
"type": "object",
Expand Down
4 changes: 2 additions & 2 deletions samples/react-basic-catalog/src/main.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,8 @@ describe('A2ui React Sandbox Integration Spec Tests (100% Parity)', () => {
await new Promise(resolve => setTimeout(resolve, 50));
});

// Verify fetch was triggered on standard path '/catalog'
expect(fetchSpy).toHaveBeenCalledWith('/catalog', expect.any(Object));
// Verify fetch was triggered on standard path 'catalog'
expect(fetchSpy).toHaveBeenCalledWith('catalog', expect.any(Object));

// Verify bridge posted back A2UI_CATALOG with resolved payload
expect(postSpy).toHaveBeenCalledWith(
Expand Down
14 changes: 12 additions & 2 deletions shell/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,19 @@
"polyfills": [],
"tsConfig": "tsconfig.json",
"inlineStyleLanguage": "scss",
"assets": ["src/favicon.svg", "src/assets", "src/config.json"],
"assets": [
"src/favicon.svg",
"src/assets",
"src/config.json",
{
"glob": "**/*",
"input": "node_modules/ng-basic-catalog/dist/ng-basic-catalog/browser",
"output": "samples/ng-basic-catalog"
}
],
"styles": ["@angular/material/prebuilt-themes/indigo-pink.css", "src/styles.scss"],
"scripts": []
"scripts": [],
"preserveSymlinks": true
},
"configurations": {
"production": {
Expand Down
16 changes: 16 additions & 0 deletions shell/e2e/settings-and-configuration.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,22 @@ test.describe('Settings and Client Configuration', () => {
await page.goto('/');
await expect(page.locator('.workspace-container')).toBeVisible();
});

test('persists configuration successfully with default relative renderer URL and loads workspace with pre-populated draft', async ({
page,
}) => {
const apiKeyInput = page.getByLabel('Gemini API Key');
await apiKeyInput.fill('test-api-key');

const saveBtn = page.getByRole('button', {name: 'Save Settings'});
await Promise.all([page.waitForURL(url => url.pathname === '/'), saveBtn.click()]);
await page.waitForLoadState('load');

await expect(page.locator('.workspace-container')).toBeVisible();

const iframe = page.frameLocator('iframe.preview-iframe');
await expect(iframe.getByRole('button', {name: 'Search Cars'})).toBeVisible();
});
});

test.describe('Enterprise & Environment Constraints', () => {
Expand Down
6 changes: 5 additions & 1 deletion shell/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
"name": "a2ui-composer-shell",
"version": "0.1.0",
"private": true,
"installConfig": {
"hoistingLimits": "workspaces"
},
"type": "module",
"scripts": {
"start": "ng serve",
"start": "yarn workspace ng-basic-catalog build && ng serve",
"build": "yarn lint && ng build",
"test": "vitest run --coverage",
"e2e": "playwright test",
Expand Down Expand Up @@ -42,6 +45,7 @@
"angular-eslint": "22.0.0",
"eslint": "10.5.0",
"jsdom": "29.1.1",
"ng-basic-catalog": "0.1.0",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this dependency is needed, since we're globbing node_modules/ng-basic-catalog/dist/ng-basic-catalog/browser as assets above.

(Also, I don't understand how this'd resolve, since ng-basic-catalog is not a real package? I'm clearly missing some yarn sorcery here)

"prettier": "3.8.4",
"typescript": "6.0.3",
"typescript-eslint": "8.61.1",
Expand Down
Loading
Loading