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.*; 020 021import org.apache.juneau.commons.beanquery.*; 022import org.apache.juneau.terminal.region.*; 023import org.apache.juneau.console.freemarker.*; 024import org.apache.juneau.console.views.*; 025import org.apache.juneau.console.views.RowAction.*; 026import org.apache.juneau.console.views.TableSpec.*; 027 028/** 029 * Builder twins of the Operations pages: P6 Jobs ({@code jobs.ftlh}) and P7 Audit ({@code audit.ftlh}). 030 * 031 * <h5 class='section'>Example:</h5> 032 * <p class='bjava'> 033 * <jk>return</jk> <jsm>twin</jsm>(<jv>req</jv>, OpsPageBuilders.<jsm>audit</jsm>()); 034 * </p> 035 */ 036@SuppressWarnings({ 037 "java:S1192" // Page-definition ids and labels repeat as inline literals by design. 038}) 039public final class OpsPageBuilders { 040 041 private OpsPageBuilders() {} 042 043 /** 044 * P6 Jobs. 045 * 046 * @param groomOutput The latest groom run's terminal. 047 * @param groomFile The latest groom run's transcript file. 048 * @return The page spec. 049 */ 050 public static PageSpec jobs(TerminalDef groomOutput, TerminalDef groomFile) { 051 return PageSpec.create().tab("ops/jobs").toolkit("views") 052 .html("restock-help", "Restocking", """ 053 <div class="jc-prose"><p>Restock adds new available pets to the store as a background job; progress shows here until it finishes. 054 Submitting twice from the same dialog runs one job. Give the card below a wait to see a cancel before anything changes, or a longer hold to see one after.</p></div>""") 055 .card(CardSpec.of("job-log", "restock").title("Restock inventory") 056 .body("submit", Map.of("endpoint", "/console/ops/jobs/restock", "submitLabel", "Restock", "fields", List.of( 057 Map.of("name", "DOG", "label", "Dogs (0-50)", "type", "number", "default", 1), 058 Map.of("name", "slowMs", "label", "Wait before restocking (ms, 0-10000)", "type", "number", "default", 0), 059 Map.of("name", "holdMs", "label", "Hold after restocking (ms, 0-10000)", "type", "number", "default", 1000)))) 060 .body("urlParam", "job")) 061 .table(TableSpec.create("jobs").dataMode(DataMode.CLIENT).dataUrl("/console/ops/jobs/rows") 062 .pollIntervalMs(2000) 063 .columns( 064 Column.create("jobId").label("Job"), 065 Column.create("submitted").label("Submitted").render("timestamp"), 066 Column.create("state").label("State").render("pill"), 067 Column.create("result.message").label("Result")) 068 .ribbon( 069 RibbonItem.dialog("restock").title("Restock").endpoint("/console/ops/jobs/restock").method(Method.POST).form("/console/ops/jobs/restock-form"), 070 RibbonItem.refresh().id("refresh"))) 071 .table(TableSpec.create("species").dataMode(DataMode.CLIENT).dataUrl("/console/ops/jobs/species") 072 .pollIntervalMs(2000) 073 .columns( 074 Column.create("species").label("Species"), 075 Column.create("available").label("Available")) 076 .detail(RowDetail.create("/console/ops/jobs/species/{id}").region(JobLogRegion.create("restock-species") 077 .submit(JobLogRegion.Submit.create("/console/ops/jobs/species/{id}/restock", "restock-species", "/console/ops/jobs/species/{id}/key") 078 .submitLabel("Restock") 079 .field(JobLogRegion.Field.of("count").label("How many (1-50)").type("number").defaultValue(1).required(true)) 080 .field(JobLogRegion.Field.of("species").type("hidden").source("row.species"))) 081 .detail(JobLogRegion.Detail.of("fieldGrid", RegionDef.Field.of("available").label("Available"))) 082 .output(JobLogRegion.Output.field("available").from("row.available")) 083 .toRegion()))) 084 .card(CardSpec.of("terminal", "groom-output").title("Groom run").body("terminal", groomOutput.toMap())) 085 .card(CardSpec.of("terminal", "groom-file").title("Groom transcript (file)").body("terminal", groomFile.toMap())) 086 .table(TableSpec.create("groom-runs").dataMode(DataMode.CLIENT).dataUrl("/console/ops/jobs/groom-rows") 087 .columns( 088 Column.create("pet").label("Pet"), 089 Column.create("submitted").label("Submitted").render("timestamp"), 090 Column.create("state").label("State").render("pill"), 091 Column.create("lines").label("Lines")) 092 .detail(RowDetail.create("/console/ops/jobs/groom-runs/{id}") 093 .region(RegionDef.create("regroom").type(RegionDef.TYPE_ROW_DETAIL).populate("petstore-regroom").allowPopulators("petstore-regroom"))) 094 .ribbon( 095 RibbonItem.dialog("groom").title("Groom").endpoint("/console/ops/jobs/groom").method(Method.POST).form("/console/ops/jobs/groom-form"), 096 RibbonItem.refresh().id("groom-refresh"))); 097 } 098 099 /** 100 * P7 Audit. 101 * 102 * @return The page spec. 103 */ 104 public static PageSpec audit() { 105 return PageSpec.create().tab("ops/audit").toolkit("views") 106 .table(TableSpec.create("audit").dataMode(DataMode.SERVER).dataUrl("/console/ops/audit/query") 107 .operators(SearchOperatorSet.standard()) 108 .defaultOrder("at", Sort.DESC) 109 .columns( 110 Column.create("at").label("When").render("timestamp").searchType(SearchType.TIMESTAMP), 111 Column.create("actor").label("Actor").searchType(SearchType.TEXT), 112 Column.create("action").label("Action").searchType(SearchType.TEXT), 113 Column.create("entity").label("Entity").searchType(SearchType.TEXT), 114 Column.create("entityId").label("Id").searchType(SearchType.TEXT), 115 Column.create("detail").label("Detail").searchType(SearchType.TEXT)) 116 .ribbon(RibbonItem.export("copy", "csv"), RibbonItem.refresh().id("refresh"))); 117 } 118}