Skip to content

[iFrame] Add the url order tracker example to the iframe catalog - #3009

Draft
josemontespg wants to merge 1 commit into
catalogs-example-srcdoc-tip-calculatorfrom
catalogs-example-url-order-tracker
Draft

josemontespg wants to merge 1 commit into
catalogs-example-srcdoc-tip-calculatorfrom
catalogs-example-url-order-tracker

Conversation

@josemontespg

@josemontespg josemontespg commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Adds url-order-tracker.json (46_url-order-tracker) to the iframe catalog examples and wires it into the Lit, Angular, and React explorer apps: a WebAppFrameUrl app that lists the orders bound from /orders, writes a status summary back to /summary for a sibling Text, dispatches order_delivered when an order status turns to delivered, and dispatches order_selected when one is clicked.

Changes

  • catalogs/iframe/examples/url-order-tracker.json & typescript/catalogs/iframe/tests/fixtures/apps/order_tracker.html: the example and the external app HTML fixture.
  • typescript/catalogs/iframe/tests/examples/url_order_tracker.test.ts, catalog.test.ts, README.md, CHANGELOG.md: iframe catalog example registration and Karma test.
  • renderers/{lit,angular,react}/a2ui_explorer: serves /a2ui-fixtures/apps/order_tracker.html, rewrites placeholder URLs in 46_url-order-tracker to the local origin, and adds Karma integration tests (46_url-order-tracker.{spec.ts,test.tsx}).

Verification

  • yarn --cwd typescript/catalogs/iframe test: 244 Karma specs pass.
  • yarn --cwd renderers/{lit,react}/a2ui_explorer test:karma: pass.
  • python3 specification/scripts/validate.py and ./scripts/fix_format.sh --check pass.

Related to #3157

@github-project-automation github-project-automation Bot moved this to Todo in A2UI Oct 5, 2026
@josemontespg
josemontespg force-pushed the catalogs-example-url-order-tracker branch from 7a9ab37 to 4fa70f1 Compare October 5, 2026 20:45
@josemontespg
josemontespg added this pull request to stack #3011 October 5, 2026 20:45

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new catalog example, url-order-tracker.json, which demonstrates a WebAppFrameUrl order tracker. It includes the corresponding fixture application order_tracker.html and comprehensive end-to-end tests to validate its functionality. The feedback suggests two robustness improvements in the fixture application: first, validating the subpath index in applyOrdersUpdate to avoid state corruption from invalid index parsing, and second, adding defensive checks for null or undefined elements in the orders array to prevent runtime errors.

Comment on lines +61 to +67
// The host diffs the array and sends each changed order as a subpath update such as "/1".
var index = Number(msg.subpath.split('/')[1]);
if (msg.value === undefined) {
orders.splice(index, 1);
} else {
orders[index] = msg.value;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

In applyOrdersUpdate, parsing the index using Number(msg.subpath.split('/')[1]) can lead to unexpected behavior if the subpath is malformed or empty (e.g., Number("") evaluates to 0, and Number(undefined) evaluates to NaN). In JavaScript, calling splice(NaN, 1) will default to removing the first element of the array (index 0), which can corrupt the state.

We should defensively validate that the extracted index is a valid non-negative integer string before parsing and using it.

Suggested change
// The host diffs the array and sends each changed order as a subpath update such as "/1".
var index = Number(msg.subpath.split('/')[1]);
if (msg.value === undefined) {
orders.splice(index, 1);
} else {
orders[index] = msg.value;
}
// The host diffs the array and sends each changed order as a subpath update such as "/1".
var parts = msg.subpath.split('/');
var indexStr = parts[1];
if (!/^\d+$/.test(indexStr)) {
return;
}
var index = Number(indexStr);
if (msg.value === undefined) {
orders.splice(index, 1);
} else {
orders[index] = msg.value;
}

Comment on lines +70 to +111
function summarize() {
return STATUSES.map(function (status) {
var count = orders.filter(function (order) {
return order.status === status;
}).length;
return count ? count + ' ' + status : '';
})
.filter(Boolean)
.join(', ');
}

function render() {
var list = document.getElementById('orders');
list.textContent = '';
orders.forEach(function (order) {
var button = document.createElement('button');
button.textContent = order.id + ' - ' + order.status;
button.addEventListener('click', function () {
send({type: 'a2ui_action', action: 'order_selected', data: {orderId: order.id}});
});
var item = document.createElement('li');
item.appendChild(button);
list.appendChild(item);
});
}

function ordersChanged() {
orders.forEach(function (order) {
var lastStatus = lastStatusById[order.id];
if (order.status === 'delivered' && lastStatus && lastStatus !== 'delivered') {
send({type: 'a2ui_action', action: 'order_delivered', data: {orderId: order.id}});
}
});
lastStatusById = {};
orders.forEach(function (order) {
lastStatusById[order.id] = order.status;
});
render();
// "summary" is listed in mutableData, so the host writes it back to /summary.
send({type: 'a2ui_data_model_change', key: 'summary', value: summarize()});
send({type: 'a2ui_size_changed', height: document.body.scrollHeight + 32});
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

To ensure robustness and adhere to defensive programming principles, we should guard against null or undefined elements in the orders array. If an element in orders is null or undefined, accessing properties like order.status or order.id will throw a runtime TypeError and crash the application loop inside the iframe.

Let's add nullish/falsy checks for order in summarize, render, and ordersChanged.

      function summarize() {
        return STATUSES.map(function (status) {
          var count = orders.filter(function (order) {
            return order && order.status === status;
          }).length;
          return count ? count + ' ' + status : '';
        })
          .filter(Boolean)
          .join(', ');
      }

      function render() {
        var list = document.getElementById('orders');
        list.textContent = '';
        orders.forEach(function (order) {
          if (!order) return;
          var button = document.createElement('button');
          button.textContent = order.id + ' - ' + order.status;
          button.addEventListener('click', function () {
            send({type: 'a2ui_action', action: 'order_selected', data: {orderId: order.id}});
          });
          var item = document.createElement('li');
          item.appendChild(button);
          list.appendChild(item);
        });
      }

      function ordersChanged() {
        orders.forEach(function (order) {
          if (!order) return;
          var lastStatus = lastStatusById[order.id];
          if (order.status === 'delivered' && lastStatus && lastStatus !== 'delivered') {
            send({type: 'a2ui_action', action: 'order_delivered', data: {orderId: order.id}});
          }
        });
        lastStatusById = {};
        orders.forEach(function (order) {
          if (order) {
            lastStatusById[order.id] = order.status;
          }
        });
        render();
        // "summary" is listed in mutableData, so the host writes it back to /summary.
        send({type: 'a2ui_data_model_change', key: 'summary', value: summarize()});
        send({type: 'a2ui_size_changed', height: document.body.scrollHeight + 32});
      }

@josemontespg
josemontespg force-pushed the catalogs-example-url-order-tracker branch 2 times, most recently from 2864ae4 to 2e7c6f0 Compare October 6, 2026 00:24
@josemontespg
josemontespg force-pushed the catalogs-example-url-order-tracker branch from 2e7c6f0 to a3aa249 Compare October 6, 2026 00:24
@josemontespg
josemontespg force-pushed the catalogs-example-url-order-tracker branch from a3aa249 to ce7bcd8 Compare October 6, 2026 00:32
@josemontespg
josemontespg removed this pull request from stack #3011 October 7, 2026 23:18
@josemontespg
josemontespg changed the base branch from catalogs-example-srcdoc-tip-calculator to main October 7, 2026 23:19
@josemontespg
josemontespg force-pushed the catalogs-example-url-order-tracker branch from ce7bcd8 to 8d2e66d Compare October 7, 2026 23:19
@josemontespg
josemontespg changed the base branch from main to catalogs-example-srcdoc-tip-calculator October 7, 2026 23:19
@josemontespg
josemontespg added this pull request to stack #3055 October 7, 2026 23:19
@josemontespg
josemontespg removed this pull request from stack #3055 October 7, 2026 23:32
@josemontespg
josemontespg force-pushed the catalogs-example-url-order-tracker branch from 8d2e66d to 2196c96 Compare October 7, 2026 23:33
@josemontespg josemontespg changed the title feat(catalogs): add the url order tracker example to the iframe catalog [iFrame] feat(catalogs): add the url order tracker example to the iframe catalog Oct 7, 2026
@josemontespg
josemontespg added this pull request to stack #3057 October 7, 2026 23:34
@josemontespg
josemontespg force-pushed the catalogs-example-url-order-tracker branch from 2196c96 to ad5b3fc Compare October 8, 2026 19:25
@josemontespg josemontespg changed the title [iFrame] feat(catalogs): add the url order tracker example to the iframe catalog [iFrame] Add the url order tracker example to the iframe catalog Oct 8, 2026
@josemontespg
josemontespg force-pushed the catalogs-example-url-order-tracker branch from ad5b3fc to c6f34cf Compare October 8, 2026 20:22
@josemontespg
josemontespg force-pushed the catalogs-example-url-order-tracker branch from c6f34cf to 41e5825 Compare October 8, 2026 20:31
@josemontespg
josemontespg added this pull request to stack #3112 October 9, 2026 18:19
@josemontespg
josemontespg removed this pull request from stack #3112 October 9, 2026 18:40
@josemontespg
josemontespg force-pushed the catalogs-example-url-order-tracker branch from b28b184 to 2a008d5 Compare October 9, 2026 18:49
@josemontespg
josemontespg added this pull request to stack #3114 October 9, 2026 18:49
@josemontespg
josemontespg force-pushed the catalogs-example-url-order-tracker branch from 2a008d5 to 34db087 Compare October 9, 2026 19:09
@josemontespg
josemontespg removed this pull request from stack #3114 October 9, 2026 19:12
@josemontespg
josemontespg added this pull request to stack #3115 October 9, 2026 19:12
@josemontespg
josemontespg force-pushed the catalogs-example-url-order-tracker branch from 34db087 to d749d56 Compare October 9, 2026 20:23
@josemontespg
josemontespg force-pushed the catalogs-example-url-order-tracker branch from d749d56 to 1ccb19f Compare October 9, 2026 22:15
@josemontespg
josemontespg force-pushed the catalogs-example-url-order-tracker branch 2 times, most recently from b3f412d to 39409f6 Compare October 9, 2026 22:43
@josemontespg
josemontespg force-pushed the catalogs-example-url-order-tracker branch from 39409f6 to 5e19185 Compare October 9, 2026 22:54
@josemontespg
josemontespg force-pushed the catalogs-example-url-order-tracker branch from 5e19185 to c094f05 Compare October 9, 2026 23:39
@josemontespg
josemontespg force-pushed the catalogs-example-url-order-tracker branch 2 times, most recently from 3b88e48 to 3d5eaf4 Compare October 12, 2026 21:29
@josemontespg
josemontespg force-pushed the catalogs-example-url-order-tracker branch from 3d5eaf4 to a9cb0bc Compare October 12, 2026 23:08
A WebAppFrameUrl app that reads the orders from bound data, writes a
status summary back through mutableData and reports selected and
delivered orders as actions. The example points at a placeholder
origin; tests/fixtures/apps/order_tracker.html is the app behind it and
tests/examples/url_order_tracker.test.ts runs the example through the
real sandbox proxy with that fixture, driving it through the host data
model.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant