Skip to main content

Petstore: Store

The Store page is the console landing page, served at /console/store. It is a dashboard: a welcome card, a "Recent orders" table whose header carries a strip of quick-stat tiles, a revenue tile, four charts and a store-hours card. Every card reads its data from a small JSON endpoint on the same resource, so the page is a good first look at how a console page is wired together. For the pattern in general, see Building a Console Page.

What this page shows​

The whole store page: welcome card, recent orders with quick stats, revenue, four chart cards and store hours

  • A datatables card in client mode with a quickStats strip: three status tiles, a segmented order breakdown and an inventory meter. The tile values are computed once per request and handed to the template.
  • A kpi card for "Revenue today".
  • Four chart cards: a line chart, a donut, a bar chart and a treemap. The treemap opens the same edit dialog as the Pets table when you click a tile.
  • An html card whose body is loaded from a fragment endpoint, so the opening hours are plain markup with no chrome.

Template​

The template is store.ftlh. Each card is a <@card> element inside one <@page>; chart cards carry their data URL in src and their options as a small JSON-style body.

<@page tab="store" toolkit="views" init=["/console/dev/cards/petstore-cards.js"]>
<@card type="chart" id="by-status" title="Pets by status" src="/console/store/stats/status">
{ kind: 'bar', x: { field: 'status' }, series: [ { field: 'count', label: 'Pets' } ] }
</@card>
<@card type="chart" id="orders-trend" title="Orders, last 30 days" src="/console/store/stats/daily">
{ kind: 'line', x: { field: 'day', label: 'Day' },
series: [ { field: 'placed', label: 'Placed' }, { field: 'delivered', label: 'Delivered', tone: 'ok' } ],
onClick: { href: '/console/orders?state=day({day})' } }
</@card>
<@card type="html" id="hours" title="Store hours" src="/console/store/fragments/hours"/>
</@page>

The init script is a petstore-specific card script that the chrome loads after the toolkit. The trend chart links each point to the Orders page filtered to that day, which is why the href uses a {day} placeholder.

Builder twin​

The same page can be built in Java. StorePageBuilders.store returns a PageSpec, and request the page with ?builder to render it through that path instead of the template.

PageSpec.create().tab("store").toolkit("views").init("/console/dev/cards/petstore-cards.js")
.card(ChartDef.bar("by-status").title("Pets by status").src("/console/store/stats/status")
.x("status").series("count", "Pets").toCardSpec())
.card(ChartDef.line("orders-trend").title("Orders, last 30 days").src("/console/store/stats/daily")
.x("day", null, "Day").series("placed", "Placed").series("delivered", "Delivered", "ok")
.onClickHref("/console/orders?state=day({day})").toCardSpec())
.htmlSrc("hours", "Store hours", "/console/store/fragments/hours");

The two renderings are required to produce the same page contract. That is what the twin test pins; see Building a Console Page for the contract itself.

The data endpoints​

StoreRest serves everything under /console/store.

EndpointReturns
GET /console/storeThe page.
GET /console/store/recent-ordersThe ten newest orders, newest first.
GET /console/store/stats/daily{day, placed, delivered} for each of the last 30 days.
GET /console/store/kpi/revenue{label, value, unit}: the summed prices of pets whose orders were delivered today.
GET /console/store/stats/species{species, count} per species, zero counts included.
GET /console/store/stats/status{status, count} per pet status.
GET /console/store/stats/pets{id, name, species, status} per pet, for the treemap.
GET /console/store/fragments/hoursThe opening hours as markup only.

Source and tests​

Source: juneau-petstore/juneau-petstore-core, classes StoreRest, StorePageBuilders (in the pages package) and the templates store.ftlh and fragments/store-hours.ftlh.

Tests: StoreRest_Test, StoreRest_EmptyStore_Test, PetstoreTwins_Test and PetstorePages_ContractTest.

See also​