├── src └── main │ ├── webapp │ ├── resources │ │ ├── js │ │ │ └── starter.js │ │ ├── favicon │ │ │ ├── favicon.ico │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── favicon-96x96.png │ │ │ ├── favicon-144x144.png │ │ │ └── favicon-196x196.png │ │ ├── images │ │ │ ├── login-bg.jpg │ │ │ └── login-bg-mobile.jpeg │ │ └── css │ │ │ └── starter.css │ ├── WEB-INF │ │ ├── beans.xml │ │ ├── jboss-web.xml │ │ ├── faces-config.xml │ │ ├── glassfish-web.xml │ │ ├── templates │ │ │ ├── template-top.xhtml │ │ │ └── template.xhtml │ │ └── web.xml │ ├── manifest.json │ ├── includes │ │ ├── menu.xhtml │ │ ├── menubar.xhtml │ │ ├── top-bar.xhtml │ │ └── controlsidebar-tabs-content.xhtml │ ├── index.xhtml │ ├── login.xhtml │ ├── car-form.xhtml │ └── car-list.xhtml │ ├── resources │ ├── starter.properties │ └── admin-config.properties │ └── java │ └── com │ └── github │ └── adminfaces │ └── starter │ ├── infra │ ├── model │ │ ├── SortOrder.java │ │ └── Filter.java │ ├── converter │ │ └── EntityConverter.java │ └── security │ │ └── LogonMB.java │ ├── util │ └── Utils.java │ ├── bean │ ├── CarFormMB.java │ └── CarListMB.java │ ├── model │ └── Car.java │ └── service │ └── CarService.java ├── Dockerfile ├── starter1.png ├── starter2.png ├── starter3.png ├── starter4.png ├── .gitignore ├── README.adoc ├── nb-configuration.xml └── pom.xml /src/main/webapp/resources/js/starter.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/starter.properties: -------------------------------------------------------------------------------- 1 | starter.version=${project.version} -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM airhacks/wildfly 2 | COPY ./target/admin-starter.war ${DEPLOYMENT_DIR} -------------------------------------------------------------------------------- /starter1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter/HEAD/starter1.png -------------------------------------------------------------------------------- /starter2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter/HEAD/starter2.png -------------------------------------------------------------------------------- /starter3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter/HEAD/starter3.png -------------------------------------------------------------------------------- /starter4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter/HEAD/starter4.png -------------------------------------------------------------------------------- /src/main/webapp/resources/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter/HEAD/src/main/webapp/resources/favicon/favicon.ico -------------------------------------------------------------------------------- /src/main/webapp/resources/images/login-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter/HEAD/src/main/webapp/resources/images/login-bg.jpg -------------------------------------------------------------------------------- /src/main/webapp/resources/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter/HEAD/src/main/webapp/resources/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /src/main/webapp/resources/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter/HEAD/src/main/webapp/resources/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /src/main/webapp/resources/favicon/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter/HEAD/src/main/webapp/resources/favicon/favicon-96x96.png -------------------------------------------------------------------------------- /src/main/webapp/resources/favicon/favicon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter/HEAD/src/main/webapp/resources/favicon/favicon-144x144.png -------------------------------------------------------------------------------- /src/main/webapp/resources/favicon/favicon-196x196.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter/HEAD/src/main/webapp/resources/favicon/favicon-196x196.png -------------------------------------------------------------------------------- /src/main/webapp/resources/images/login-bg-mobile.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter/HEAD/src/main/webapp/resources/images/login-bg-mobile.jpeg -------------------------------------------------------------------------------- /src/main/resources/admin-config.properties: -------------------------------------------------------------------------------- 1 | admin.loginPage=login.jsf 2 | admin.indexPage=index.jsf 3 | admin.renderControlSidebar=true 4 | admin.controlSidebar.showOnMobile=true 5 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/main/java/com/github/adminfaces/starter/infra/model/SortOrder.java: -------------------------------------------------------------------------------- 1 | package com.github.adminfaces.starter.infra.model; 2 | 3 | /** 4 | * Created by rmpestano on 10/31/14. 5 | */ 6 | public enum SortOrder { 7 | 8 | ASCENDING, DESCENDING, UNSORTED; 9 | 10 | public boolean isAscending() { 11 | return ASCENDING.equals(this); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jboss-web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | /admin-starter 4 | 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | 3 | .project 4 | 5 | .classpath 6 | 7 | .settings/ 8 | 9 | 10 | 11 | # IntelliJ 12 | 13 | *.iml 14 | 15 | *.ipr 16 | 17 | *.iws 18 | 19 | .idea 20 | 21 | .settings 22 | 23 | 24 | 25 | # Maven 26 | 27 | target/ 28 | 29 | 30 | 31 | #Gradle 32 | 33 | .gradle 34 | 35 | 36 | 37 | # TestNG 38 | 39 | test-output/ 40 | 41 | 42 | 43 | 44 | *.log 45 | 46 | #linux te files 47 | *~ 48 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/faces-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | org.omnifaces.resourcehandler.CombinedResourceHandler 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/glassfish-web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /admin-starter 5 | 6 | 7 | 8 | Keep a copy of the generated servlet class' java code. 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/webapp/resources/css/starter.css: -------------------------------------------------------------------------------- 1 | .sidebar-form { 2 | border-radius: 3px; 3 | border: 1px solid #374850; 4 | margin: 10px 10px; 5 | } 6 | .sidebar-form, .sidebar-menu>li.header { 7 | overflow: hidden; 8 | text-overflow: clip; 9 | } 10 | 11 | #userImage { 12 | float: left; 13 | width: 25px; 14 | height: 25px; 15 | border-radius: 50%; 16 | margin-right: 10px; 17 | margin-top: -2px; 18 | } 19 | 20 | ul.dropdown-menu > li.user-header { 21 | height: auto!important; 22 | } 23 | 24 | a.dropdown-toggle { 25 | background-color: #3c8dbc!important; 26 | } 27 | 28 | a#logout { 29 | color: #3c8dbc!important; 30 | background: transparent; 31 | } 32 | 33 | @media (max-width: 768px) { 34 | body .control-sidebar { 35 | padding-top:100px; 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/webapp/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Admin Starter", 3 | "name": "AdminFaces Starter Application", 4 | "icons": [ 5 | { 6 | "src": "/resources/favicon/favicon-196x196.png", 7 | "sizes": "196x196", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/resources/favicon/favicon-144x144.png", 12 | "sizes": "144x144", 13 | "type": "image/png" 14 | }, 15 | { 16 | "src": "/resources/favicon/favicon-96x96.png", 17 | "sizes": "96x96", 18 | "type": "image/png" 19 | } 20 | ], 21 | "theme_color": "#3c8dbc", 22 | "background_color": "#ffffff", 23 | "scope": "/admin-starter/", 24 | "start_url": "/admin-starter/index.xhtml", 25 | "display": "standalone" 26 | } -------------------------------------------------------------------------------- /src/main/webapp/includes/menu.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | Home 11 | 12 | 13 | 14 | General 15 | 16 | 17 | 18 | 19 | Cars 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = AdminFaces Starter project 2 | 3 | 4 | A simple project to get you started with https://github.com/adminfaces[AdminFaces^]. 5 | 6 | .Login page 7 | image:starter1.png[link="https://github.com/adminfaces/admin-starter/blob/master/starter1.png"] 8 | 9 | .Car list 10 | image:starter2.png[link="https://raw.githubusercontent.com/adminfaces/admin-starter/master/starter2.png"] 11 | 12 | .Car form 13 | image:starter3.png[link="https://raw.githubusercontent.com/adminfaces/admin-starter/master/starter3.png"] 14 | 15 | .Car form responsive 16 | image:starter4.png[link="https://raw.githubusercontent.com/adminfaces/admin-starter/master/starter4.png"] 17 | 18 | == Running 19 | 20 | It should run in any JavaEE 6 or greater application server. 21 | 22 | You can also run via wildfly-swarm with command `mvn wildfly-swarm:run -Pswarm`. 23 | 24 | Or using docker: 25 | 26 | ---- 27 | docker run -it -p 8080:8080 rmpestano/admin-starter 28 | ---- 29 | 30 | The application is available at http://localhost:8080/admin-starter 31 | 32 | == Demo 33 | 34 | A live demo is available on https://adminfaces.github.io/admin-starter/[Openshift here^] 35 | -------------------------------------------------------------------------------- /nb-configuration.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 16 | WildFly 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/main/webapp/index.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | Welcome to the AdminFaces Starter Project! 14 | 15 | Integrating , and 17 | into your 18 | application. 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/main/webapp/includes/menubar.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | Home 11 | 12 | 13 | 14 | Cars 16 | 17 | 18 | 19 | 20 | 21 | 22 | List cars 23 | 24 | 25 | 26 | 27 | 28 | New car 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/main/java/com/github/adminfaces/starter/util/Utils.java: -------------------------------------------------------------------------------- 1 | package com.github.adminfaces.starter.util; 2 | 3 | import com.github.adminfaces.starter.model.Car; 4 | import org.omnifaces.util.Messages; 5 | 6 | import jakarta.annotation.PostConstruct; 7 | import jakarta.enterprise.context.ApplicationScoped; 8 | import jakarta.enterprise.inject.Produces; 9 | import jakarta.faces.application.FacesMessage; 10 | import java.io.Serializable; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.stream.IntStream; 14 | 15 | /** 16 | * Created by rmpestano on 07/02/17. 17 | */ 18 | @ApplicationScoped 19 | public class Utils implements Serializable { 20 | 21 | private List cars; 22 | 23 | 24 | @PostConstruct 25 | public void init() { 26 | cars = new ArrayList<>(); 27 | IntStream.rangeClosed(1, 50) 28 | .forEach(i -> cars.add(create(i))); 29 | } 30 | 31 | private static Car create(int i) { 32 | return new Car(i).model("model " + i).name("name" + i).price(Double.valueOf(i)); 33 | } 34 | 35 | public static void addDetailMessage(String message) { 36 | addDetailMessage(message, null); 37 | } 38 | 39 | public static void addDetailMessage(String message, FacesMessage.Severity severity) { 40 | 41 | FacesMessage facesMessage = Messages.create("").detail(message).get(); 42 | if (severity != null && severity != FacesMessage.SEVERITY_INFO) { 43 | facesMessage.setSeverity(severity); 44 | } 45 | Messages.add(null, facesMessage); 46 | } 47 | 48 | @Produces 49 | public List getCars() { 50 | return cars; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/github/adminfaces/starter/infra/converter/EntityConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.adminfaces.starter.infra.converter; 2 | 3 | 4 | import jakarta.faces.component.UIComponent; 5 | import jakarta.faces.context.FacesContext; 6 | import jakarta.faces.convert.Converter; 7 | import jakarta.faces.convert.FacesConverter; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | import java.util.Map.Entry; 11 | import java.util.Set; 12 | import java.util.UUID; 13 | 14 | @FacesConverter(value = "entityConverter") 15 | public class EntityConverter implements Converter { 16 | 17 | @Override 18 | public String getAsString(FacesContext context, UIComponent component, Object entity) { 19 | if (entity == null || "".equals(entity)) { 20 | return null; 21 | } 22 | 23 | if (!getEntityMap(context).containsKey(entity)) { 24 | String uuid = UUID.randomUUID().toString(); 25 | getEntityMap(context).put(entity, uuid); 26 | return uuid; 27 | } else { 28 | return getEntityMap(context).get(entity); 29 | } 30 | } 31 | 32 | @Override 33 | public Object getAsObject(FacesContext context, UIComponent component, String uuid) { 34 | Set> entries = getEntityMap(context).entrySet(); 35 | for (Entry entry : entries) { 36 | if (entry.getValue().equals(uuid)) { 37 | return entry.getKey(); 38 | } 39 | } 40 | return null; 41 | } 42 | 43 | @SuppressWarnings("unchecked") 44 | private Map getEntityMap(FacesContext context) { 45 | Map viewMap = context.getViewRoot().getViewMap(); 46 | Map entities = (Map) viewMap.get("entities"); 47 | if (entities == null) { 48 | entities = new HashMap<>(); 49 | viewMap.put("entities", entities); 50 | } 51 | return entities; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/github/adminfaces/starter/infra/model/Filter.java: -------------------------------------------------------------------------------- 1 | package com.github.adminfaces.starter.infra.model; 2 | 3 | 4 | import java.io.Serializable; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | /** 9 | * Created by rmpestano on 9/7/14. 10 | * class which holds database pagination metadata 11 | */ 12 | public class Filter { 13 | private T entity; 14 | private int first; 15 | private int pageSize; 16 | private String sortField; 17 | private SortOrder sortOrder; 18 | private Map params = new HashMap(); 19 | 20 | 21 | public Filter() { 22 | } 23 | 24 | public Filter(T entity) { 25 | this.entity = entity; 26 | } 27 | 28 | public Filter setFirst(int first) { 29 | this.first = first; 30 | return this; 31 | } 32 | 33 | public int getFirst() { 34 | return first; 35 | } 36 | 37 | public Filter setPageSize(int pageSize) { 38 | this.pageSize = pageSize; 39 | return this; 40 | } 41 | 42 | public int getPageSize() { 43 | return pageSize; 44 | } 45 | 46 | public Filter setSortField(String sortField) { 47 | this.sortField = sortField; 48 | return this; 49 | } 50 | 51 | public String getSortField() { 52 | return sortField; 53 | } 54 | 55 | public Filter setSortOrder(SortOrder sortOrder) { 56 | this.sortOrder = sortOrder; 57 | return this; 58 | } 59 | 60 | public SortOrder getSortOrder() { 61 | return sortOrder; 62 | } 63 | 64 | public Filter setParams(Map params) { 65 | this.params = params; 66 | return this; 67 | } 68 | 69 | public Map getParams() { 70 | return params; 71 | } 72 | 73 | public T getEntity() { 74 | return entity; 75 | } 76 | 77 | public Filter setEntity(T entity) { 78 | this.entity = entity; 79 | return this; 80 | } 81 | 82 | public Filter addParam(String key, Object value) { 83 | getParams().put(key, value); 84 | return this; 85 | } 86 | 87 | public boolean hasParam(String key) { 88 | return getParams().containsKey(key) && getParam(key) != null; 89 | } 90 | 91 | public Object getParam(String key) { 92 | return getParams().get(key); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/github/adminfaces/starter/bean/CarFormMB.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this template, choose Tools | Templates 3 | * and open the template in the editor. 4 | */ 5 | package com.github.adminfaces.starter.bean; 6 | 7 | import com.github.adminfaces.starter.model.Car; 8 | import com.github.adminfaces.starter.service.CarService; 9 | import jakarta.inject.Inject; 10 | import jakarta.inject.Named; 11 | import org.omnifaces.cdi.ViewScoped; 12 | import org.omnifaces.util.Faces; 13 | 14 | import java.io.Serializable; 15 | 16 | import static com.github.adminfaces.starter.util.Utils.addDetailMessage; 17 | import static com.github.adminfaces.template.util.Assert.has; 18 | 19 | /** 20 | * @author rmpestano 21 | */ 22 | @Named 23 | @ViewScoped 24 | public class CarFormMB implements Serializable { 25 | private Integer id; 26 | private Car car; 27 | 28 | @Inject 29 | CarService carService; 30 | 31 | public void init() { 32 | if (Faces.isAjaxRequest()) { 33 | return; 34 | } 35 | if (has(id)) { 36 | car = carService.findById(id); 37 | } else { 38 | car = new Car(); 39 | } 40 | } 41 | 42 | public Integer getId() { 43 | return id; 44 | } 45 | 46 | public void setId(Integer id) { 47 | this.id = id; 48 | } 49 | 50 | public Car getCar() { 51 | return car; 52 | } 53 | 54 | public void setCar(Car car) { 55 | this.car = car; 56 | } 57 | 58 | 59 | public void remove() { 60 | if (has(car) && has(car.getId())) { 61 | carService.remove(car); 62 | addDetailMessage("Car " + car.getModel() 63 | + " removed successfully"); 64 | Faces.getFlash().setKeepMessages(true); 65 | Faces.redirect("car-list.jsf"); 66 | } 67 | } 68 | 69 | public void save() { 70 | String msg; 71 | if (car.getId() == null) { 72 | carService.insert(car); 73 | msg = "Car " + car.getModel() + " created successfully"; 74 | } else { 75 | carService.update(car); 76 | msg = "Car " + car.getModel() + " updated successfully"; 77 | } 78 | addDetailMessage(msg); 79 | } 80 | 81 | public void clear() { 82 | car = new Car(); 83 | id = null; 84 | } 85 | 86 | public boolean isNew() { 87 | return car == null || car.getId() == null; 88 | } 89 | 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/github/adminfaces/starter/infra/security/LogonMB.java: -------------------------------------------------------------------------------- 1 | package com.github.adminfaces.starter.infra.security; 2 | 3 | import com.github.adminfaces.template.session.AdminSession; 4 | import org.omnifaces.util.Faces; 5 | 6 | import jakarta.enterprise.context.SessionScoped; 7 | import jakarta.enterprise.inject.Specializes; 8 | import jakarta.inject.Named; 9 | import java.io.IOException; 10 | import java.io.Serializable; 11 | 12 | import static com.github.adminfaces.starter.util.Utils.addDetailMessage; 13 | import com.github.adminfaces.template.config.AdminConfig; 14 | import jakarta.inject.Inject; 15 | 16 | /** 17 | * Created by rmpestano on 12/20/14. 18 | * 19 | * This is just a login example. 20 | * 21 | * AdminSession uses isLoggedIn to determine if user must be redirect to login page or not. 22 | * By default AdminSession isLoggedIn always resolves to true so it will not try to redirect user. 23 | * 24 | * If you already have your authorization mechanism which controls when user must be redirect to initial page or logon 25 | * you can skip this class. 26 | */ 27 | @Named 28 | @SessionScoped 29 | @Specializes 30 | public class LogonMB extends AdminSession implements Serializable { 31 | 32 | private String currentUser; 33 | private String email; 34 | private String password; 35 | private boolean remember; 36 | @Inject 37 | private AdminConfig adminConfig; 38 | 39 | 40 | public void login() throws IOException { 41 | currentUser = email; 42 | addDetailMessage("Logged in successfully as " + email + ""); 43 | Faces.getExternalContext().getFlash().setKeepMessages(true); 44 | Faces.redirect(adminConfig.getIndexPage()); 45 | } 46 | 47 | @Override 48 | public boolean isLoggedIn() { 49 | 50 | return currentUser != null; 51 | } 52 | 53 | public String getEmail() { 54 | return email; 55 | } 56 | 57 | public void setEmail(String email) { 58 | this.email = email; 59 | } 60 | 61 | public String getPassword() { 62 | return password; 63 | } 64 | 65 | public void setPassword(String password) { 66 | this.password = password; 67 | } 68 | 69 | public boolean isRemember() { 70 | return remember; 71 | } 72 | 73 | public void setRemember(boolean remember) { 74 | this.remember = remember; 75 | } 76 | 77 | public String getCurrentUser() { 78 | return currentUser; 79 | } 80 | 81 | public void setCurrentUser(String currentUser) { 82 | this.currentUser = currentUser; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/templates/template-top.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | Admin Starter 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Admin Starter 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 47 | Copyright (C) 2017 - AdminFaces 48 | 49 | 50 | 51 | #{msg['starter.version']} 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/templates/template.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | Admin Starter 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Admin Starter 23 | 24 | 25 | 26 | Admin 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 51 | Copyright (C) 2017 - AdminFaces 52 | 53 | 54 | 55 | #{msg['starter.version']} 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/main/java/com/github/adminfaces/starter/model/Car.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this template, choose Tools | Templates 3 | * and open the template in the editor. 4 | */ 5 | package com.github.adminfaces.starter.model; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * @author rmpestano 11 | */ 12 | public class Car implements Serializable, Comparable { 13 | 14 | private Integer id; 15 | private String model; 16 | private String name; 17 | private Double price; 18 | 19 | public Car() { 20 | } 21 | 22 | public Car(Integer id) { 23 | this.id = id; 24 | } 25 | 26 | public String getModel() { 27 | return model; 28 | } 29 | 30 | public Double getPrice() { 31 | return price; 32 | } 33 | 34 | public Integer getId() { 35 | return id; 36 | } 37 | 38 | public String getName() { 39 | return name; 40 | } 41 | 42 | public void setModel(String model) { 43 | this.model = model; 44 | } 45 | 46 | public void setName(String name) { 47 | this.name = name; 48 | } 49 | 50 | public void setPrice(Double price) { 51 | this.price = price; 52 | } 53 | 54 | public void setId(Integer id) { 55 | this.id = id; 56 | } 57 | 58 | public Car model(String model) { 59 | this.model = model; 60 | return this; 61 | } 62 | 63 | public Car price(Double price) { 64 | this.price = price; 65 | return this; 66 | } 67 | 68 | public Car name(String name) { 69 | this.name = name; 70 | return this; 71 | } 72 | 73 | @Override 74 | public int hashCode() { 75 | final int prime = 31; 76 | int result = 1; 77 | result = prime * result + ((id == null) ? 0 : id.hashCode()); 78 | return result; 79 | } 80 | 81 | @Override 82 | public boolean equals(Object obj) { 83 | if (this == obj) 84 | return true; 85 | if (obj == null) 86 | return false; 87 | if (getClass() != obj.getClass()) 88 | return false; 89 | Car other = (Car) obj; 90 | if (id == null) { 91 | if (other.id != null) 92 | return false; 93 | } else if (!id.equals(other.id)) 94 | return false; 95 | return true; 96 | } 97 | 98 | public boolean hasModel() { 99 | return model != null && !"".equals(model.trim()); 100 | } 101 | 102 | public boolean hasName() { 103 | return name != null && !"".equals(name.trim()); 104 | } 105 | 106 | @Override 107 | public int compareTo(Car o) { 108 | return this.id.compareTo(o.getId()); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/main/webapp/includes/top-bar.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 29 | #{logonMB.currentUser} 30 | 31 | 32 | 33 | 34 | 36 | 37 | 38 | #{logonMB.currentUser} 39 | Subtitle 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | com.github.adminfaces 7 | admin-starter 8 | 0.1-SNAPSHOT 9 | war 10 | admin-starter 11 | 12 | 13 | UTF-8 14 | 1.6.1 15 | 16 | 17 | 18 | 19 | jakarta.platform 20 | jakarta.jakartaee-web-api 21 | 9.1.0 22 | provided 23 | 24 | 25 | com.github.adminfaces 26 | admin-template 27 | ${adminfaces.version} 28 | 29 | 30 | org.primefaces 31 | primefaces 32 | 11.0.0 33 | jakarta 34 | 35 | 36 | 37 | 38 | 39 | true 40 | src/main/resources 41 | 42 | 43 | src/main/docs 44 | true 45 | 46 | 47 | 48 | 49 | true 50 | src/test/resources 51 | 52 | 53 | src/test/java/ 54 | 55 | 56 | 57 | 58 | maven-compiler-plugin 59 | 3.3 60 | 61 | 1.8 62 | 1.8 63 | 64 | 65 | 66 | org.apache.maven.plugins 67 | maven-war-plugin 68 | 3.3.2 69 | 70 | 71 | admin-starter 72 | 73 | 74 | 75 | 76 | 77 | snapshots 78 | libs-snapshot 79 | https://oss.sonatype.org/content/repositories/snapshots 80 | 81 | 82 | prime-repo 83 | PrimeFaces Maven Repository 84 | http://repository.primefaces.org 85 | default 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 30 7 | 8 | 9 | 10 | jakarta.faces.PROJECT_STAGE 11 | Production 12 | 13 | 14 | primefaces.THEME 15 | admin 16 | 17 | 18 | primefaces.FONT_AWESOME 19 | true 20 | 21 | 22 | primefaces.MOVE_SCRIPTS_TO_BOTTOM 23 | true 24 | 25 | 26 | jakarta.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL 27 | true 28 | 29 | 30 | com.sun.faces.numberOfLogicalViews 31 | 6 32 | 33 | 34 | com.sun.faces.numberOfViewsInSession 35 | 6 36 | 37 | 38 | org.omnifaces.VIEW_SCOPE_MANAGER_MAX_ACTIVE_VIEW_SCOPES 39 | 6 40 | 41 | 42 | index.html 43 | 44 | 45 | Faces Servlet 46 | jakarta.faces.webapp.FacesServlet 47 | 1 48 | 49 | 50 | 51 | gzipResponseFilter 52 | org.omnifaces.filter.GzipResponseFilter 53 | 54 | The threshold size in bytes. Must be a number between 0 and 9999. Defaults to 150. 55 | 56 | threshold 57 | 200 58 | 59 | 60 | 61 | gzipResponseFilter 62 | Faces Servlet 63 | REQUEST 64 | ERROR 65 | 66 | 67 | 68 | Faces Servlet 69 | *.jsf 70 | 71 | 72 | 73 | 74 | 403 75 | /403.jsf 76 | 77 | 78 | com.github.adminfaces.template.exception.AccessDeniedException 79 | /403.jsf 80 | 81 | 82 | 404 83 | /404.jsf 84 | 85 | 86 | 500 87 | /500.jsf 88 | 89 | 90 | java.lang.Throwable 91 | /500.jsf 92 | 93 | 94 | jakarta.faces.application.ViewExpiredException 95 | /expired.jsf 96 | 97 | 98 | jakarta.persistence.OptimisticLockException 99 | /optimistic.jsf 100 | 101 | 102 | -------------------------------------------------------------------------------- /src/main/java/com/github/adminfaces/starter/bean/CarListMB.java: -------------------------------------------------------------------------------- 1 | package com.github.adminfaces.starter.bean; 2 | 3 | import com.github.adminfaces.starter.infra.model.Filter; 4 | import com.github.adminfaces.starter.model.Car; 5 | import com.github.adminfaces.starter.service.CarService; 6 | import com.github.adminfaces.template.exception.BusinessException; 7 | import org.omnifaces.cdi.ViewScoped; 8 | import org.primefaces.model.FilterMeta; 9 | import org.primefaces.model.LazyDataModel; 10 | import org.primefaces.model.SortMeta; 11 | import org.primefaces.model.SortOrder; 12 | 13 | import jakarta.annotation.PostConstruct; 14 | import jakarta.inject.Inject; 15 | import jakarta.inject.Named; 16 | import java.io.Serializable; 17 | import java.util.Arrays; 18 | import java.util.List; 19 | import java.util.Map; 20 | import java.util.stream.Collectors; 21 | 22 | import static com.github.adminfaces.starter.util.Utils.addDetailMessage; 23 | import static com.github.adminfaces.template.util.Assert.has; 24 | 25 | /** 26 | * Created by rmpestano on 12/02/17. 27 | */ 28 | @Named 29 | @ViewScoped 30 | public class CarListMB implements Serializable { 31 | 32 | @Inject 33 | CarService carService; 34 | 35 | Integer id; 36 | 37 | LazyDataModel cars; 38 | 39 | Filter filter = new Filter<>(new Car()); 40 | 41 | List selectedCars; //cars selected in checkbox column 42 | 43 | List filteredValue;// datatable filteredValue attribute (column filters) 44 | 45 | @PostConstruct 46 | public void initDataModel() { 47 | cars = new LazyDataModel() { 48 | 49 | @Override 50 | public int count(Map map) { 51 | return (int) carService.count(filter); 52 | } 53 | 54 | @Override 55 | public List load(int first, int pageSize, Map sortMap, Map filterMap) { 56 | if (has(sortMap)) { 57 | sortMap.entrySet().stream() 58 | .findAny() 59 | .ifPresent(sortField -> { 60 | filter.setSortField(sortField.getKey()); 61 | filter.setSortOrder(getSortOrder(SortOrder.ASCENDING == sortField.getValue().getOrder(), sortField.getValue().getOrder() == SortOrder.DESCENDING)); 62 | } 63 | ); 64 | } 65 | filter.setFirst(first).setPageSize(pageSize); 66 | if (has(filterMap)) { 67 | filter.setParams(filterMap.entrySet().stream() 68 | .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)) 69 | ); 70 | } 71 | return carService.paginate(filter); 72 | } 73 | 74 | private com.github.adminfaces.starter.infra.model.SortOrder getSortOrder(boolean asc, boolean desc) { 75 | return asc ? 76 | com.github.adminfaces.starter.infra.model.SortOrder.ASCENDING : desc ? 77 | com.github.adminfaces.starter.infra.model.SortOrder.DESCENDING : com.github.adminfaces.starter.infra.model.SortOrder.UNSORTED; 78 | } 79 | 80 | @Override 81 | public Car getRowData(String key) { 82 | return carService.findById(Integer.valueOf(key)); 83 | } 84 | 85 | @Override 86 | public String getRowKey(Car car) { 87 | return car.getId().toString(); 88 | } 89 | }; 90 | } 91 | 92 | public void clear() { 93 | filter = new Filter<>(new Car()); 94 | } 95 | 96 | public List completeModel(String query) { 97 | return carService.getModels(query); 98 | } 99 | 100 | public void findCarById(Integer id) { 101 | if (id == null) { 102 | throw new BusinessException("Provide Car ID to load"); 103 | } 104 | selectedCars = Arrays.asList(carService.findById(id)); 105 | } 106 | 107 | public void delete() { 108 | int numCars = 0; 109 | for (Car selectedCar : selectedCars) { 110 | numCars++; 111 | carService.remove(selectedCar); 112 | } 113 | selectedCars.clear(); 114 | addDetailMessage(numCars + " cars deleted successfully!"); 115 | } 116 | 117 | public List getSelectedCars() { 118 | return selectedCars; 119 | } 120 | 121 | public List getFilteredValue() { 122 | return filteredValue; 123 | } 124 | 125 | public void setFilteredValue(List filteredValue) { 126 | this.filteredValue = filteredValue; 127 | } 128 | 129 | public void setSelectedCars(List selectedCars) { 130 | this.selectedCars = selectedCars; 131 | } 132 | 133 | public LazyDataModel getCars() { 134 | return cars; 135 | } 136 | 137 | public void setCars(LazyDataModel cars) { 138 | this.cars = cars; 139 | } 140 | 141 | public Filter getFilter() { 142 | return filter; 143 | } 144 | 145 | public void setFilter(Filter filter) { 146 | this.filter = filter; 147 | } 148 | 149 | public Integer getId() { 150 | return id; 151 | } 152 | 153 | public void setId(Integer id) { 154 | this.id = id; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/main/webapp/login.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | Admin Starter 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 82 | 83 | 84 | 85 | 86 | 87 | AdminStarter 88 | 89 | 90 | 91 | 92 | Sign in to start your session 93 | 94 | 95 | 96 | 99 | 100 | 101 | 102 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 115 | 116 | 117 | 118 | 119 | 120 | - OR - 121 | Sign in using 123 | Facebook 124 | Sign in using 126 | Google+ 127 | 128 | 129 | 130 | I forgot my password 131 | Register a new membership 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /src/main/webapp/includes/controlsidebar-tabs-content.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | Recent Activity 11 | 12 | 13 | 14 | 15 | 16 | 17 | Langdon's Birthday 18 | 19 | Will be 23 on April 24th 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | Frodo Updated His Profile 29 | 30 | New phone +1(800)555-1234 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | Nora Joined Mailing List 40 | 41 | nora@example.com 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Cron Job 254 Executed 51 | 52 | Execution time 5 seconds 53 | 54 | 55 | 56 | 57 | 58 | Tasks Progress 59 | 60 | 61 | 62 | 63 | Custom Template Design 64 | 70% 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Update Resume 76 | 95% 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | Laravel Integration 88 | 50% 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | Back End Framework 100 | 68% 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | General Settings 114 | 115 | 116 | 117 | Report panel usage 118 | 119 | 120 | 121 | 122 | Some information about this general settings option 123 | 124 | 125 | 126 | 127 | 128 | Allow mail redirect 129 | 130 | 131 | 132 | 133 | Other sets of options are available 134 | 135 | 136 | 137 | 138 | 139 | Expose author name in posts 140 | 141 | 142 | 143 | 144 | Allow the user to show his name in blog posts 145 | 146 | 147 | 148 | Chat Settings 149 | 150 | 151 | 152 | Show me as online 153 | 154 | 155 | 156 | 157 | 158 | 159 | Turn off notifications 160 | 161 | 162 | 163 | 164 | 165 | 166 | Delete chat history 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /src/main/java/com/github/adminfaces/starter/service/CarService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this template, choose Tools | Templates 3 | * and open the template in the editor. 4 | */ 5 | package com.github.adminfaces.starter.service; 6 | 7 | import com.github.adminfaces.starter.infra.model.Filter; 8 | import com.github.adminfaces.starter.infra.model.SortOrder; 9 | import com.github.adminfaces.starter.model.Car; 10 | import com.github.adminfaces.template.exception.BusinessException; 11 | 12 | import jakarta.ejb.Stateless; 13 | import jakarta.inject.Inject; 14 | import java.io.Serializable; 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.function.Predicate; 18 | import java.util.stream.Collectors; 19 | 20 | import static com.github.adminfaces.template.util.Assert.has; 21 | 22 | /** 23 | * @author rmpestano 24 | * Car Business logic 25 | */ 26 | @Stateless 27 | public class CarService implements Serializable { 28 | 29 | @Inject 30 | List allCars; 31 | 32 | public List listByModel(String model) { 33 | return allCars.stream() 34 | .filter(c -> c.getModel().equalsIgnoreCase(model)) 35 | .collect(Collectors.toList()); 36 | 37 | } 38 | 39 | public List paginate(Filter filter) { 40 | List pagedCars = new ArrayList<>(); 41 | if(has(filter.getSortOrder()) && !SortOrder.UNSORTED.equals(filter.getSortOrder())) { 42 | pagedCars = allCars.stream(). 43 | sorted((c1, c2) -> { 44 | if (filter.getSortOrder().isAscending()) { 45 | return c1.getId().compareTo(c2.getId()); 46 | } else { 47 | return c2.getId().compareTo(c1.getId()); 48 | } 49 | }) 50 | .collect(Collectors.toList()); 51 | } 52 | 53 | int page = filter.getFirst() + filter.getPageSize(); 54 | if (!pagedCars.isEmpty() && filter.getParams().isEmpty()) { 55 | pagedCars = allCars.subList(filter.getFirst(), Math.min(page, allCars.size())); 56 | return pagedCars; 57 | } 58 | 59 | List> predicates = configFilter(filter); 60 | 61 | List pagedList = allCars.stream().filter(predicates 62 | .stream().reduce(Predicate::or).orElse(t -> true)) 63 | .collect(Collectors.toList()); 64 | 65 | if (page < pagedList.size()) { 66 | pagedList = pagedList.subList(filter.getFirst(), page); 67 | } 68 | 69 | if (has(filter.getSortField())) { 70 | pagedList = pagedList.stream(). 71 | sorted((c1, c2) -> { 72 | boolean asc = SortOrder.ASCENDING.equals(filter.getSortOrder()); 73 | if (asc) { 74 | return c1.getId().compareTo(c2.getId()); 75 | } else { 76 | return c2.getId().compareTo(c1.getId()); 77 | } 78 | }) 79 | .collect(Collectors.toList()); 80 | } 81 | return pagedList; 82 | } 83 | 84 | private List> configFilter(Filter filter) { 85 | List> predicates = new ArrayList<>(); 86 | if (filter.hasParam("id")) { 87 | Predicate idPredicate = (Car c) -> c.getId().equals(filter.getParam("id")); 88 | predicates.add(idPredicate); 89 | } 90 | 91 | if (filter.hasParam("minPrice") && filter.hasParam("maxPrice")) { 92 | Predicate minMaxPricePredicate = (Car c) -> c.getPrice() 93 | >= Double.parseDouble((String) filter.getParam("minPrice")) && c.getPrice() 94 | <= Double.parseDouble((String) filter.getParam("maxPrice")); 95 | predicates.add(minMaxPricePredicate); 96 | } else if (filter.hasParam("minPrice")) { 97 | Predicate minPricePredicate = (Car c) -> c.getPrice() 98 | >= Double.parseDouble((String) filter.getParam("minPrice")); 99 | predicates.add(minPricePredicate); 100 | } else if (filter.hasParam("maxPrice")) { 101 | Predicate maxPricePredicate = (Car c) -> c.getPrice() 102 | <= Double.parseDouble((String) filter.getParam("maxPrice")); 103 | predicates.add(maxPricePredicate); 104 | } 105 | 106 | if (has(filter.getEntity())) { 107 | Car filterEntity = filter.getEntity(); 108 | if (has(filterEntity.getModel())) { 109 | Predicate modelPredicate = (Car c) -> c.getModel().toLowerCase().contains(filterEntity.getModel().toLowerCase()); 110 | predicates.add(modelPredicate); 111 | } 112 | 113 | if (has(filterEntity.getPrice())) { 114 | Predicate pricePredicate = (Car c) -> c.getPrice().equals(filterEntity.getPrice()); 115 | predicates.add(pricePredicate); 116 | } 117 | 118 | if (has(filterEntity.getName())) { 119 | Predicate namePredicate = (Car c) -> c.getName().toLowerCase().contains(filterEntity.getName().toLowerCase()); 120 | predicates.add(namePredicate); 121 | } 122 | } 123 | return predicates; 124 | } 125 | 126 | public List getModels(String query) { 127 | return allCars.stream().filter(c -> c.getModel() 128 | .toLowerCase().contains(query.toLowerCase())) 129 | .map(Car::getModel) 130 | .collect(Collectors.toList()); 131 | } 132 | 133 | public void insert(Car car) { 134 | validate(car); 135 | car.setId(allCars.stream() 136 | .mapToInt(Car::getId) 137 | .max() 138 | .getAsInt()+1); 139 | allCars.add(car); 140 | } 141 | 142 | public void validate(Car car) { 143 | BusinessException be = new BusinessException(); 144 | if (!car.hasModel()) { 145 | be.addException(new BusinessException("Car model cannot be empty")); 146 | } 147 | if (!car.hasName()) { 148 | be.addException(new BusinessException("Car name cannot be empty")); 149 | } 150 | 151 | if (!has(car.getPrice())) { 152 | be.addException(new BusinessException("Car price cannot be empty")); 153 | } 154 | 155 | if (allCars.stream().filter(c -> c.getName().equalsIgnoreCase(car.getName()) 156 | && c.getId() != c.getId()).count() > 0) { 157 | be.addException(new BusinessException("Car name must be unique")); 158 | } 159 | if(has(be.getExceptionList())) { 160 | throw be; 161 | } 162 | } 163 | 164 | 165 | public void remove(Car car) { 166 | allCars.remove(car); 167 | } 168 | 169 | public long count(Filter filter) { 170 | return allCars.stream() 171 | .filter(configFilter(filter).stream() 172 | .reduce(Predicate::or).orElse(t -> true)) 173 | .count(); 174 | } 175 | 176 | public Car findById(Integer id) { 177 | return allCars.stream() 178 | .filter(c -> c.getId().equals(id)) 179 | .findFirst() 180 | .orElseThrow(() -> new BusinessException("Car not found with id " + id)); 181 | } 182 | 183 | public void update(Car car) { 184 | validate(car); 185 | allCars.remove(car); 186 | allCars.add(car); 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /src/main/webapp/car-form.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Car form 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 30 | 31 | 32 | 35 | 37 | 38 | 39 | 40 | 44 | 45 | 48 | 51 | 53 | 55 | 56 | 57 | 58 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 116 | 119 | 121 | 123 | 124 | 125 | 126 | 129 | 130 | 131 | 132 | 133 | 134 | 136 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /src/main/webapp/car-list.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | Find cars by name, price and model 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 31 | 36 | 37 | 38 | 39 | 42 | 43 | 44 | 47 | 51 | 52 | 53 | 58 | 59 | 60 | 61 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | Find Car by id: 78 | 79 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | #{c.name} 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | #{c.price} 120 | 121 | 122 | 123 | 124 | 125 | 127 | 129 | 130 | 131 | 132 | 133 | 134 | 136 | 138 | ID: #{car.id} - Name: #{car.name} - Model: #{car.model} 139 | 140 | 141 | 142 | 143 | 144 | 145 | --------------------------------------------------------------------------------
38 | #{logonMB.currentUser} 39 | Subtitle 40 |
Sign in to start your session
- OR -
Will be 23 on April 24th
New phone +1(800)555-1234
nora@example.com
Execution time 5 seconds
122 | Some information about this general settings option 123 |
133 | Other sets of options are available 134 |
144 | Allow the user to show his name in blog posts 145 |