001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.petstore.console.pages; 018 019import java.util.function.*; 020 021import org.apache.juneau.commons.beanquery.*; 022import org.apache.juneau.console.views.*; 023import org.apache.juneau.console.views.TableSpec.*; 024import org.apache.juneau.petstore.console.users.UsersRest.*; 025import org.apache.juneau.petstore.dto.*; 026 027/** 028 * The expandable row details of the console tables, shared by the page builders (which only need the declaration) and 029 * the resources that serve them (which pass a real lookup). 030 * 031 * <p> 032 * A bean-backed detail lists its fields explicitly, so the resource that serves it never depends on having been 033 * attached to a table. Each field list equals the columns of the table it opens from, hidden ones included. 034 * 035 * <h2 class='section'>Example:</h2> 036 * <p class='bjava'> 037 * <jc>// A page builder attaches the declaration; the resource serves it with a store lookup.</jc> 038 * TableSpec.<jsm>create</jsm>(<js>"orders"</js>).detail(RowDetails.<jsm>order</jsm>()); 039 * </p> 040 */ 041@SuppressWarnings({ 042 "java:S1192" // Column and field names repeat as inline literals by design. 043}) 044public final class RowDetails { 045 046 private RowDetails() {} 047 048 private static <T> Function<String,T> none() { 049 return id -> null; 050 } 051 052 /** @return The Pets table detail, for building a page. */ 053 public static RowDetail pet() { 054 return pet(none()); 055 } 056 057 /** 058 * The Pets table detail: Details, this pet's orders and its history. 059 * 060 * @param lookup Finds a pet by row id, or returns <jk>null</jk>. 061 * @return A new detail. 062 */ 063 public static RowDetail pet(Function<String,Pet> lookup) { 064 return RowDetail.fromBean(Pet.class, lookup).basePath("/console/pets").title("{name}").columns(3) 065 .section("Details", "id", "name", "species", "status", "price", "tags") 066 .label("price", "Price (USD)") 067 .tab(DetailTab.table("Orders", ordersView("pets-orders", "/console/pets/orders/rows")).id("orders").scopeParam("petId").countFromRows()) 068 .tab(DetailTab.table("History", historyView()).id("history").scopeParam("petId").countFromRows()); 069 } 070 071 /** @return The Sold table detail, for building a page. */ 072 public static RowDetail soldPet() { 073 return soldPet(none()); 074 } 075 076 /** 077 * The Sold table detail: the columns that table shows, and this pet's orders. 078 * 079 * @param lookup Finds a pet by row id, or returns <jk>null</jk>. 080 * @return A new detail. 081 */ 082 public static RowDetail soldPet(Function<String,Pet> lookup) { 083 return RowDetail.fromBean(Pet.class, lookup).key("soldPet").basePath("/console/pets").title("{name}").columns(3) 084 .section("Details", "id", "name", "species", "price") 085 .label("price", "Price (USD)") 086 .tab(DetailTab.table("Orders", ordersView("sold-orders", "/console/pets/orders/rows")).id("orders").scopeParam("petId").countFromRows()); 087 } 088 089 /** @return The Orders and Store tables' detail, for building a page. */ 090 public static RowDetail order() { 091 return order(none()); 092 } 093 094 /** 095 * The Orders and Store recent-orders detail: Details and the ordered pet. 096 * 097 * @param lookup Finds an order by row id, or returns <jk>null</jk>. 098 * @return A new detail. 099 */ 100 public static RowDetail order(Function<String,Order> lookup) { 101 return RowDetail.fromBean(Order.class, lookup).basePath("/console/orders").title("Order {id}").columns(2) 102 .section("Details", "id", "petId", "shipDate", "status") 103 .label("petId", "Pet") 104 .tab(DetailTab.table("Pet", TableSpec.create("order-pet").rowType("Pet").dataMode(DataMode.CLIENT).dataUrl("/console/orders/pet/rows") 105 .columns( 106 Column.create("id").label("Id"), 107 Column.create("name").label("Name").href("/console/pets/{id}/summary"), 108 Column.create("species").label("Species"), 109 Column.create("status").label("Status"), 110 Column.create("price").label("Price (USD)").render(Render.of("decimal").meta("places", 2)))) 111 .id("pet").scopeParam("orderId").countFromRows()); 112 } 113 114 /** @return The Users table detail, for building a page. */ 115 public static RowDetail user() { 116 return user(none()); 117 } 118 119 /** 120 * The Users table detail: Details and the orders this user placed. It serves {@code UserView}, so a password, 121 * email or phone never leaves the server. 122 * 123 * @param lookup Finds a user by row id (the username), or returns <jk>null</jk>. 124 * @return A new detail. 125 */ 126 public static RowDetail user(Function<String,UserView> lookup) { 127 return RowDetail.fromBean(UserView.class, lookup).key("user").basePath("/console/users").title("{username}").columns(2) 128 .section("Details", "username", "firstName", "lastName", "userStatus") 129 .label("userStatus", "Status") 130 .tab(DetailTab.table("Orders", ordersView("user-orders", "/console/users/orders/rows")).id("orders").scopeParam("username").countFromRows()); 131 } 132 133 /** @return The Pending changes table detail. */ 134 public static RowDetail change() { 135 return RowDetail.inline().title("Change {id}").section("Details", "id", "summary", "author", "state", "message"); 136 } 137 138 /** @return The Audit table detail. */ 139 public static RowDetail audit() { 140 return RowDetail.inline().title("{action} {entity} {entityId}") 141 .section("Details", "id", "at", "actor", "action", "entity", "entityId", "detail"); 142 } 143 144 /** @return The pet History table detail. */ 145 public static RowDetail history() { 146 return RowDetail.inline().title("{action}").section("Details", "id", "at", "actor", "action", "detail"); 147 } 148 149 private static TableSpec ordersView(String id, String dataUrl) { 150 return TableSpec.create(id).rowType("Order").dataMode(DataMode.CLIENT).dataUrl(dataUrl) 151 .columns( 152 Column.create("id").label("Order").href("/console/pets/{petId}/orders/{id}").searchType(SearchType.NUMERIC), 153 Column.create("shipDate").label("Ship date").render("date").searchType(SearchType.TEXT), 154 Column.create("status").label("Status").render(PillRenders.orderStatus()).searchType(SearchType.ENUM)); 155 } 156 157 private static TableSpec historyView() { 158 return TableSpec.create("pets-history").rowType("AuditEntry").dataMode(DataMode.CLIENT).dataUrl("/console/pets/history/rows") 159 .columns( 160 Column.create("at").label("When").render("timestamp").searchType(SearchType.TEXT), 161 Column.create("actor").label("Actor").searchType(SearchType.TEXT), 162 Column.create("action").label("Action").render(PillRenders.auditAction()).searchType(SearchType.ENUM), 163 Column.create("detail").label("Detail").searchType(SearchType.TEXT)); 164 } 165}