├── .gitignore ├── .travis.yml ├── Dockerfile ├── Dockerfile-payara ├── Dockerfile-tomee ├── README.adoc ├── build-and-run.sh ├── docker ├── build.sh ├── run.sh └── standalone.conf ├── nb-configuration.xml ├── nbactions.xml ├── pom.xml ├── src ├── main │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── adminfaces │ │ │ └── starter │ │ │ ├── bean │ │ │ ├── CarFormMB.java │ │ │ ├── CarListMB.java │ │ │ ├── InitAppMB.java │ │ │ └── Lists.java │ │ │ ├── infra │ │ │ ├── persistence │ │ │ │ └── EntityManagerProducer.java │ │ │ └── security │ │ │ │ └── LogonMB.java │ │ │ ├── model │ │ │ └── Car.java │ │ │ └── service │ │ │ ├── CarRepository.java │ │ │ └── CarService.java │ ├── resources │ │ ├── META-INF │ │ │ ├── apache-deltaspike.properties │ │ │ └── persistence.xml │ │ ├── admin-config.properties │ │ └── messages.properties │ └── webapp │ │ ├── WEB-INF │ │ ├── beans.xml │ │ ├── faces-config.xml │ │ ├── glassfish-web.xml │ │ ├── jboss-web.xml │ │ ├── templates │ │ │ ├── template-top.xhtml │ │ │ └── template.xhtml │ │ └── web.xml │ │ ├── car-form.xhtml │ │ ├── car-list.xhtml │ │ ├── includes │ │ ├── controlsidebar-tabs-content.xhtml │ │ ├── menu.xhtml │ │ ├── menubar.xhtml │ │ └── top-bar.xhtml │ │ ├── index.xhtml │ │ ├── login.xhtml │ │ ├── public │ │ └── index.xhtml │ │ └── resources │ │ ├── css │ │ └── starter.css │ │ ├── favicon │ │ ├── favicon-144x144.png │ │ ├── favicon-16x16.png │ │ ├── favicon-196x196.png │ │ ├── favicon-32x32.png │ │ ├── favicon-96x96.png │ │ └── favicon.ico │ │ └── images │ │ ├── login-bg-mobile.jpeg │ │ └── login-bg.jpg └── test │ ├── java │ └── com │ │ └── github │ │ └── adminfaces │ │ ├── ft │ │ ├── AdminFt.java │ │ └── pages │ │ │ ├── CarFormPage.java │ │ │ ├── CarListPage.java │ │ │ ├── IndexPage.java │ │ │ ├── LogonPage.java │ │ │ └── fragments │ │ │ ├── LeftMenu.java │ │ │ └── SearchDialog.java │ │ ├── it │ │ └── AdminIt.java │ │ └── util │ │ └── Deployments.java │ └── resources │ ├── arquillian.xml │ ├── chameleon │ └── default │ │ └── containers.yaml │ └── datasets │ └── cars.yml ├── starter1.png ├── starter2.png ├── starter3.png ├── starter4.png └── starter5.png /.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 | /.apt_generated_tests/ 49 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | addons: 3 | chrome: stable 4 | language: java 5 | jdk: oraclejdk8 6 | sudo: required 7 | services: 8 | - docker 9 | cache: 10 | directories: 11 | - "$HOME/.m2/repository" 12 | - "$HOME/.arquillian" 13 | script: 14 | - mvn clean test -Ptests -Darquillian.browser=chromeheadless -Pcoverage 15 | - mvn sonar:sonar -Dsonar.organization=adminfaces -Dsonar.host.url=https://sonarcloud.io 16 | -Dsonar.login=${SONAR_KEY} 17 | after_success: 18 | - mvn clean package 19 | - docker login -u rmpestano -p ${pass} 20 | - mvn dockerfile:build -Pdocker 21 | - mvn dockerfile:push -Pdocker 22 | env: 23 | global: 24 | - secure: to/7n4WZyvPce0S+sL3qP3XDMX99gjau2Kt+SVuZoEJuEjC+jEDLf2dYqtBQF7k2d+hMfnEGBJjz43pJDMEOR+qV3BasOyjtwBXABDymQEI5aPs0KkpJwSvGG0ykHdmga1KgX8j+zzjOudNAFjWTkO5hKbilLrTSh0eaGdWo3Arasd5N1bHHBGE9yjDz5AvIMT43dtzcHJ0zHgxnHldpkiARCsoACjMNDYj7QjP8YgtfKvIclwxqWttHnk4xtePuKN0H7MkRvE3aFRr2UDHOygIRToIq+eswtUKPOZiJyPpXOjvkxSXF8hctfPpwBrDhw4yQBfLqn7dU44ncW6GBiIm4WQtxDHvCusQH8o8i1rT+EVjLDUFN3pwjj7ijRhFRd9zblrKpwWrqU1MH72rmbQxV/TJ4Gp90dNXuGtcWO/48mQvEaScXJDeMB3FG/XP9Wyd+vohgJYfvl2l88GVSadm9Y+BWPhIFCN2w2mm7RhgzdhraWMV8EedDgBxi1kYNe9AfQczy8BHtb8gjAw1kZ/C69nZidYUJX9+p8YBlGbz2qPHFlJjMeaYUjVG/QqDa1xOdjuckwFy26blaTaPgXwJDgFVQGV5uOUtmqdAADGoyeMQELDPU9XgYNqbhCjspyk/j6AZgzR9TvFiPwFTKHyHMfkW59XmLO1svjUhlbi4= 25 | - secure: Rd3ojYgKhw+TB/+po31BsW8ilhllQYvqcdcxh8mHCDT/7GYjn5qHekWOTA/TpFmy9N+FtBxCdjf18InlAfzhPBLSsDdm34EvamUPs3lfcBDR0CSZEXqbNFAqj4lD8W04S+V7Px5OQqvVvttXDqDYSGfZne+0bwYwHIEN/UKe2II5rGz65NaBDtKa4U5RQ9IjWcrawg8U6dJfigu34YBD/jjNbESrgw/sxRkS/WMuX9ayJE/gvpHTdXH0Kx5uM0tcR5Sh3XG2PzxjufaAYWWIZMoIpiciwh+qTU556cse3SDms/SUbT9Rwn6Pba5KdxV0uwUmQCX25lWyQEHYcDmS7UEme9mbaxtFpO3u3WrjC5NmTxPIvzjzfSTc96Z6PsnfifSd03JhW9wdh5oc3//J/9+6ZzQ5OqJ5zR5kTDcYoh209CjCMRUi/Byed1e2SrqxsTamr+JkxOq0WwBwAcDFdsMJIdWl6cFVSbKqO8gvTDH+5b4xTTCP/mqei2HWNycyIqoQxPKL/Ijh2BHb8u7tfRYmnFjcbokoLSSi5pZGIE3cruAV/8KNLlR/kLYyd8PCmBeyQhawXtb/XV0/PGrUp61xb87xNvGPngXv5ZzEy+ZmZSwO+BQnJ+hYSKRYTod3Jdsv2FS8Xy+bVHTJRJlqtvuA0nogRrXVIlOcqZVblSk= 26 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rmpestano/wildfly:16.0.0 2 | MAINTAINER Rafael Pestano 3 | 4 | COPY ./docker/standalone.conf ${WILDFLY_HOME}/bin/ 5 | 6 | COPY ./target/admin-starter.war ${DEPLOYMENT_DIR} 7 | -------------------------------------------------------------------------------- /Dockerfile-payara: -------------------------------------------------------------------------------- 1 | FROM payara/server-full:5.191 2 | 3 | COPY ./target/admin-starter.war $DEPLOY_DIR 4 | -------------------------------------------------------------------------------- /Dockerfile-tomee: -------------------------------------------------------------------------------- 1 | FROM tomee:8-jre-8.0.0-M2-plus 2 | 3 | COPY ./target/admin-starter.war /usr/local/tomee/webapps/admin-starter.war 4 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = AdminFaces Starter Persistence 2 | :toc: preamble 3 | :sectanchors: 4 | :sectlink: 5 | :numbered: 6 | :tip-caption: :bulb: 7 | :note-caption: :information_source: 8 | :important-caption: :heavy_exclamation_mark: 9 | :caution-caption: :fire: 10 | :warning-caption: :warning: 11 | 12 | image:https://travis-ci.org/adminfaces/admin-starter-persistence.svg[Build Status (Travis CI), link=https://travis-ci.org/adminfaces/admin-starter-persistence] 13 | image:https://sonarcloud.io/api/project_badges/measure?project=com.github.adminfaces:admin-starter&metric=alert_status["Sonar", link="https://sonarcloud.io/dashboard?id=com.github.adminfaces%3Aadmin-starter"] 14 | 15 | A simple project to get you started with https://github.com/adminfaces[AdminFaces^] using https://github.com/adminfaces/admin-persistence[Admin Persistence^] for utility persistence layer. 16 | 17 | .Login page 18 | image:starter1.png[link="https://raw.githubusercontent.com/adminfaces/admin-starter-persistence/master/starter1.png"] 19 | 20 | .Car list 21 | image:starter2.png[link="https://raw.githubusercontent.com/adminfaces/admin-starter-persistence/master/starter2.png"] 22 | 23 | .Car search 24 | image:starter5.png[link="https://raw.githubusercontent.com/adminfaces/admin-starter-persistence/master/starter5.png"] 25 | 26 | .Car form 27 | image:starter3.png[link="https://raw.githubusercontent.com/adminfaces/admin-starter-persistence/master/starter3.png"] 28 | 29 | .Car form responsive 30 | image:starter4.png[link="https://raw.githubusercontent.com/adminfaces/admin-starter-persistence/master/starter4.png"] 31 | 32 | 33 | 34 | == Running 35 | 36 | Run `mvn clean package` and deploy on any JavaEE 6 or greater application server. 37 | 38 | IMPORTANT: If you are not running on `JBoss/Wildfly` you'll need to configure the datasource declared in https://github.com/adminfaces/admin-starter-persistence/blob/master/src/main/resources/META-INF/persistence.xml[persistence.xml^]. 39 | 40 | TIP: To run on `Java EE 6` app server you'll need to downgrade OmniFaces to version `2.1`. 41 | 42 | You can also run via http://wildfly-swarm.io/[wildfly-swarm^] with command `mvn wildfly-swarm:run -Pswarm`. 43 | 44 | Or using docker: 45 | 46 | ---- 47 | docker run -it -p 8080:8080 rmpestano/admin-starter-persistence 48 | ---- 49 | 50 | [TIP] 51 | ==== 52 | 53 | Use the `bash build-and-run.sh` to easily start the application on a docker container. 54 | 55 | TIP: To run on `Payara` or `Tomee` just replace Dockerfile content with `Dockerfile-payara` or `Dockerfile-tomee` and run the build-and-run script. 56 | 57 | ==== 58 | 59 | 60 | The application is available at http://localhost:8080/admin-starter 61 | 62 | == Demo 63 | 64 | A live demo is available on https://adminfaces.github.io/admin-starter/[Openshift here^] 65 | 66 | == Test 67 | 68 | To run tests execute following maven command: 69 | 70 | * `mvn test -Ptests` for all tests 71 | * `mvn test -Pblackbox` for functional tests 72 | * `mvn test -Pwhitebox` for integration tests 73 | 74 | See the following video to see the tests in action: https://youtu.be/9_khZVsDO0Y 75 | 76 | -------------------------------------------------------------------------------- /build-and-run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | mvn clean package && cd docker && bash build.sh && bash run.sh 3 | -------------------------------------------------------------------------------- /docker/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker build -t rmpestano/admin-starter-persistence ../ 3 | -------------------------------------------------------------------------------- /docker/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker run -it --rm --name admin-starter -p 8080:8080 rmpestano/admin-starter-persistence 3 | -------------------------------------------------------------------------------- /docker/standalone.conf: -------------------------------------------------------------------------------- 1 | ## -*- shell-script -*- ###################################################### 2 | ## ## 3 | ## JBoss Bootstrap Script Configuration ## 4 | ## ## 5 | ############################################################################## 6 | 7 | # 8 | # This file is optional; it may be removed if not needed. 9 | # 10 | 11 | # 12 | # Specify the maximum file descriptor limit, use "max" or "maximum" to use 13 | # the default, as queried by the system. 14 | # 15 | # Defaults to "maximum" 16 | # 17 | #MAX_FD="maximum" 18 | 19 | # 20 | # Specify the profiler configuration file to load. 21 | # 22 | # Default is to not load profiler configuration file. 23 | # 24 | #PROFILER="" 25 | 26 | # 27 | # Specify the location of the Java home directory. If set then $JAVA will 28 | # be defined to $JAVA_HOME/bin/java, else $JAVA will be "java". 29 | # 30 | #JAVA_HOME="/opt/java/jdk" 31 | 32 | # 33 | # Specify the exact Java VM executable to use. 34 | # 35 | #JAVA="" 36 | 37 | if [ "x$JBOSS_MODULES_SYSTEM_PKGS" = "x" ]; then 38 | JBOSS_MODULES_SYSTEM_PKGS="org.jboss.byteman" 39 | fi 40 | 41 | # Uncomment the following line to prevent manipulation of JVM options 42 | # by shell scripts. 43 | # 44 | #PRESERVE_JAVA_OPTS=true 45 | 46 | # 47 | # Specify options to pass to the Java VM. 48 | # 49 | if [ "x$JAVA_OPTS" = "x" ]; then 50 | JAVA_OPTS="-Xms750m -Xmx750m -XX:MetaspaceSize=128M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true" 51 | JAVA_OPTS="$JAVA_OPTS -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Duser.timezone=GMT-03:00" 52 | JAVA_OPTS="$JAVA_OPTS -Djboss.modules.system.pkgs=$JBOSS_MODULES_SYSTEM_PKGS -Djava.awt.headless=true" 53 | else 54 | echo "JAVA_OPTS already set in environment; overriding default settings with values: $JAVA_OPTS" 55 | fi 56 | 57 | # Sample JPDA settings for remote socket debugging 58 | #JAVA_OPTS="$JAVA_OPTS -agentlib:jdwp=transport=dt_socket,address=8787,server=y,suspend=n" 59 | 60 | # Sample JPDA settings for shared memory debugging 61 | #JAVA_OPTS="$JAVA_OPTS -agentlib:jdwp=transport=dt_shmem,server=y,suspend=n,address=jboss" 62 | 63 | # Uncomment to not use JBoss Modules lockless mode 64 | #JAVA_OPTS="$JAVA_OPTS -Djboss.modules.lockless=false" 65 | 66 | # Uncomment to gather JBoss Modules metrics 67 | #JAVA_OPTS="$JAVA_OPTS -Djboss.modules.metrics=true" 68 | 69 | # Uncomment this to run with a security manager enabled 70 | # SECMGR="true" 71 | 72 | # Uncomment this in order to be able to run WildFly on FreeBSD 73 | # when you get "epoll_create function not implemented" message in dmesg output 74 | #JAVA_OPTS="$JAVA_OPTS -Djava.nio.channels.spi.SelectorProvider=sun.nio.ch.PollSelectorProvider" 75 | -------------------------------------------------------------------------------- /nb-configuration.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | WildFly 22 | false 23 | 24 | 25 | -------------------------------------------------------------------------------- /nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CUSTOM-test 5 | test 6 | 7 | test 8 | 9 | 10 | tests 11 | wildfly-remote 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.github.adminfaces 6 | admin-starter 7 | 0.1-SNAPSHOT 8 | war 9 | admin-starter 10 | 11 | 12 | UTF-8 13 | 1.0.2 14 | 5.1.8.Final 15 | 1.8.2 16 | wildfly:15.0.1.Final:managed 17 | chrome 18 | false 19 | ${project.build.directory}/surefire-reports 20 | ${project.build.directory}/jacoco.exec 21 | java 22 | jacoco 23 | reuseReports 24 | 25 | 26 | 27 | 28 | 29 | javax 30 | javaee-api 31 | 7.0 32 | provided 33 | 34 | 35 | org.primefaces 36 | primefaces 37 | 7.0 38 | 39 | 40 | com.github.adminfaces 41 | admin-template 42 | ${adminfaces.version} 43 | 44 | 45 | com.github.adminfaces 46 | admin-theme 47 | ${adminfaces.version} 48 | 49 | 50 | 51 | org.primefaces.extensions 52 | primefaces-extensions 53 | 6.1.1 54 | 55 | 56 | 57 | com.github.adminfaces 58 | admin-persistence 59 | 1.0.7 60 | 61 | 62 | 63 | org.omnifaces 64 | omnifaces 65 | 3.2 66 | 67 | 68 | 69 | 70 | org.hibernate 71 | hibernate-core 72 | ${version.hibernate} 73 | provided 74 | 75 | 76 | org.hibernate 77 | hibernate-validator 78 | 5.1.1.Final 79 | provided 80 | 81 | 82 | org.hibernate 83 | hibernate-entitymanager 84 | ${version.hibernate} 85 | provided 86 | 87 | 88 | 89 | 90 | junit 91 | junit 92 | 4.12 93 | test 94 | 95 | 96 | 97 | org.assertj 98 | assertj-core 99 | 3.6.2 100 | test 101 | 102 | 103 | 104 | org.arquillian.universe 105 | arquillian-junit 106 | pom 107 | test 108 | 109 | 110 | 111 | org.arquillian.universe 112 | arquillian-chameleon 113 | test 114 | pom 115 | 116 | 117 | 118 | org.arquillian.universe 119 | arquillian-graphene 120 | test 121 | pom 122 | 123 | 124 | org.arquillian.universe 125 | arquillian-persistence 126 | pom 127 | test 128 | 129 | 130 | xml-apis 131 | xml-apis 132 | 1.4.01 133 | test 134 | 135 | 136 | 137 | com.google.guava 138 | guava 139 | 23.0 140 | test 141 | 142 | 143 | 144 | 145 | 146 | 147 | org.jboss.arquillian.selenium 148 | selenium-bom 149 | 3.13.0 150 | import 151 | pom 152 | 153 | 154 | org.arquillian 155 | arquillian-universe 156 | 1.2.0.2 157 | import 158 | pom 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | true 167 | src/main/resources 168 | 169 | 170 | src/main/docs 171 | true 172 | 173 | 174 | 175 | 176 | true 177 | src/test/resources 178 | 179 | 180 | src/test/java/ 181 | 182 | 183 | 184 | 185 | maven-compiler-plugin 186 | 3.3 187 | 188 | 1.8 189 | 1.8 190 | 191 | 192 | 193 | org.bsc.maven 194 | maven-processor-plugin 195 | 3.3.2 196 | 197 | 198 | process 199 | generate-sources 200 | 201 | process 202 | 203 | 204 | 205 | org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor 206 | 207 | 208 | 209 | 210 | 211 | 212 | org.hibernate 213 | hibernate-jpamodelgen 214 | 5.2.12.Final 215 | 216 | 217 | 218 | 219 | org.sonarsource.scanner.maven 220 | sonar-maven-plugin 221 | 3.4.0.905 222 | 223 | 224 | admin-starter 225 | 226 | 227 | 228 | 229 | tests 230 | 231 | 232 | 233 | maven-surefire-plugin 234 | 2.19.1 235 | 236 | reversealphabetical 237 | 238 | **/*It.java 239 | **/*Ft.java 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | whitebox 249 | 250 | 251 | 252 | maven-surefire-plugin 253 | 2.19.1 254 | 255 | reversealphabetical 256 | 257 | **/*It.java 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | blackbox 267 | 268 | 269 | 270 | maven-surefire-plugin 271 | 2.19.1 272 | 273 | reversealphabetical 274 | 275 | **/*Ft.java 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | wildfly-remote 285 | 286 | wildfly:15.0.1.Final:remote 287 | 288 | 289 | 290 | 291 | swarm 292 | 293 | 2018.3.3 294 | 295 | 296 | 297 | 298 | org.wildfly.swarm 299 | jsf 300 | ${version.wildfly-swarm} 301 | 302 | 303 | org.wildfly.swarm 304 | cdi 305 | ${version.wildfly-swarm} 306 | 307 | 308 | org.wildfly.swarm 309 | ejb 310 | ${version.wildfly-swarm} 311 | 312 | 313 | 314 | org.wildfly.swarm 315 | jpa 316 | ${version.wildfly-swarm} 317 | 318 | 319 | com.h2database 320 | h2 321 | 1.4.196 322 | 323 | 324 | 325 | 326 | 327 | 328 | maven-compiler-plugin 329 | 3.5 330 | 331 | 1.8 332 | 1.8 333 | 334 | 335 | 336 | maven-surefire-plugin 337 | 2.19.1 338 | 339 | true 340 | 341 | 342 | 343 | org.apache.maven.plugins 344 | maven-war-plugin 345 | 2.6 346 | 347 | false 348 | 349 | 350 | 351 | org.wildfly.swarm 352 | wildfly-swarm-plugin 353 | ${version.wildfly-swarm} 354 | 355 | 356 | package 357 | 358 | 359 | start 360 | 361 | 362 | stop 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | jboss-public-repository-group 372 | JBoss Public Repository Group 373 | https://repository.jboss.org/nexus/content/groups/public/ 374 | 375 | true 376 | never 377 | 378 | 379 | true 380 | daily 381 | 382 | 383 | 384 | 385 | 386 | 387 | docker 388 | 389 | 390 | 391 | 392 | com.spotify 393 | dockerfile-maven-plugin 394 | 1.3.6 395 | 396 | 397 | default 398 | 399 | build 400 | push 401 | 402 | 403 | 404 | 405 | rmpestano/admin-starter-persistence 406 | latest 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | coverage 415 | 416 | 0.7.9 417 | 418 | 419 | 420 | 421 | org.jacoco 422 | jacoco-maven-plugin 423 | ${jacoco.version} 424 | 425 | 426 | 427 | prepare-agent 428 | 429 | 430 | 431 | report 432 | prepare-package 433 | 434 | report 435 | 436 | 437 | 438 | 439 | 440 | com/github/adminfaces/starter/bean/*.class 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | org.arquillian.universe 449 | arquillian-jacoco 450 | test 451 | pom 452 | 453 | 454 | org.jacoco 455 | org.jacoco.core 456 | ${jacoco.version} 457 | test 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | snapshots 467 | libs-snapshot 468 | https://oss.sonatype.org/content/repositories/snapshots 469 | 470 | 471 | prime-repo 472 | PrimeFaces Maven Repository 473 | http://repository.primefaces.org 474 | default 475 | 476 | 477 | 478 | 479 | -------------------------------------------------------------------------------- /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.persistence.bean.BeanService; 8 | import com.github.adminfaces.persistence.bean.CrudMB; 9 | import com.github.adminfaces.starter.model.Car; 10 | import com.github.adminfaces.starter.service.CarService; 11 | import org.omnifaces.cdi.ViewScoped; 12 | import org.omnifaces.util.Faces; 13 | 14 | import javax.inject.Named; 15 | import java.io.Serializable; 16 | import java.util.logging.Level; 17 | 18 | /** 19 | * @author rmpestano 20 | */ 21 | @Named 22 | @ViewScoped 23 | @BeanService(CarService.class)//use annotation instead of setter 24 | public class CarFormMB extends CrudMB implements Serializable { 25 | 26 | public void afterRemove() { 27 | try { 28 | addDetailMsg("Car " + entity.getModel() 29 | + " removed successfully"); 30 | Faces.redirect("car-list.xhtml"); 31 | clear(); 32 | sessionFilter.clear(CarListMB.class.getName());//removes filter saved in session for CarListMB. 33 | } catch (Exception e) { 34 | log.log(Level.WARNING, "", e); 35 | } 36 | } 37 | 38 | @Override 39 | public void afterInsert() { 40 | addDetailMsg("Car " + entity.getModel() + " created successfully"); 41 | } 42 | 43 | @Override 44 | public void afterUpdate() { 45 | addDetailMsg("Car " + entity.getModel() + " updated successfully"); 46 | } 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/github/adminfaces/starter/bean/CarListMB.java: -------------------------------------------------------------------------------- 1 | package com.github.adminfaces.starter.bean; 2 | 3 | import static com.github.adminfaces.persistence.util.Messages.addDetailMessage; 4 | import static com.github.adminfaces.persistence.util.Messages.getMessage; 5 | import static com.github.adminfaces.template.util.Assert.has; 6 | 7 | import java.io.Serializable; 8 | import java.util.List; 9 | 10 | import javax.inject.Inject; 11 | import javax.inject.Named; 12 | 13 | import org.omnifaces.cdi.ViewScoped; 14 | 15 | import com.github.adminfaces.persistence.bean.CrudMB; 16 | import com.github.adminfaces.persistence.service.CrudService; 17 | import com.github.adminfaces.persistence.service.Service; 18 | import com.github.adminfaces.starter.model.Car; 19 | import com.github.adminfaces.starter.service.CarService; 20 | import com.github.adminfaces.template.exception.BusinessException; 21 | 22 | /** 23 | * Created by rmpestano on 12/02/17. 24 | */ 25 | @Named 26 | @ViewScoped 27 | public class CarListMB extends CrudMB implements Serializable { 28 | 29 | @Inject 30 | CarService carService; 31 | 32 | @Inject 33 | @Service 34 | CrudService carCrudService; //generic injection example 35 | 36 | @Inject 37 | public void initService() { 38 | setCrudService(carService); 39 | } 40 | 41 | public List completeModel(String query) { 42 | List result = carService.getModels(query); 43 | return result; 44 | } 45 | 46 | public void findCarById(Integer id) { 47 | if (id == null) { 48 | throw new BusinessException("Provide Car ID to load"); 49 | } 50 | Car carFound = carCrudService.findById(id); 51 | if (carFound == null) { 52 | throw new BusinessException(String.format("No car found with id %s", id)); 53 | } 54 | selectionList.add(carFound); 55 | getFilter().addParam("id", id); 56 | } 57 | 58 | public void delete() { 59 | int numCars = 0; 60 | for (Car selectedCar : selectionList) { 61 | numCars++; 62 | carService.remove(selectedCar); 63 | } 64 | selectionList.clear(); 65 | addDetailMessage(numCars + " cars deleted successfully!"); 66 | clear(); 67 | } 68 | 69 | public String getSearchCriteria() { 70 | StringBuilder sb = new StringBuilder(21); 71 | 72 | String nameParam = null; 73 | Car carFilter = filter.getEntity(); 74 | 75 | Integer idParam = null; 76 | if (filter.hasParam("id")) { 77 | idParam = filter.getIntParam("id"); 78 | } 79 | 80 | if (has(idParam)) { 81 | sb.append("id: ").append(idParam).append(", "); 82 | } 83 | 84 | if (filter.hasParam("name")) { 85 | nameParam = filter.getStringParam("name"); 86 | } else if (has(carFilter) && carFilter.getName() != null) { 87 | nameParam = carFilter.getName(); 88 | } 89 | 90 | if (has(nameParam)) { 91 | sb.append("name: ").append(nameParam).append(", "); 92 | } 93 | 94 | String modelParam = null; 95 | if (filter.hasParam("model")) { 96 | modelParam = filter.getStringParam("model"); 97 | } else if (has(carFilter) && carFilter.getModel() != null) { 98 | modelParam = carFilter.getModel(); 99 | } 100 | 101 | if (has(modelParam)) { 102 | sb.append("model: ").append(modelParam).append(", "); 103 | } 104 | 105 | Double priceParam = null; 106 | if (filter.hasParam("price")) { 107 | priceParam = filter.getDoubleParam("price"); 108 | } else if (has(carFilter) && carFilter.getModel() != null) { 109 | priceParam = carFilter.getPrice(); 110 | } 111 | 112 | if (has(priceParam)) { 113 | sb.append("price: ").append(priceParam).append(", "); 114 | } 115 | 116 | if (filter.hasParam("minPrice")) { 117 | sb.append("").append(getMessage("label.minPrice")).append(": ").append(filter.getParam("minPrice")).append(", "); 118 | } 119 | 120 | if (filter.hasParam("maxPrice")) { 121 | sb.append("").append(getMessage("label.maxPrice")).append(": ").append(filter.getParam("maxPrice")).append(", "); 122 | } 123 | 124 | int commaIndex = sb.lastIndexOf(","); 125 | 126 | if (commaIndex != -1) { 127 | sb.deleteCharAt(commaIndex); 128 | } 129 | 130 | if (sb.toString().trim().isEmpty()) { 131 | return "No search criteria"; 132 | } 133 | 134 | return sb.toString(); 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /src/main/java/com/github/adminfaces/starter/bean/InitAppMB.java: -------------------------------------------------------------------------------- 1 | package com.github.adminfaces.starter.bean; 2 | 3 | import com.github.adminfaces.persistence.service.CrudService; 4 | import com.github.adminfaces.persistence.service.Service; 5 | import com.github.adminfaces.starter.model.Car; 6 | 7 | import javax.annotation.PostConstruct; 8 | import javax.ejb.Singleton; 9 | import javax.ejb.Startup; 10 | import javax.inject.Inject; 11 | import java.io.Serializable; 12 | import java.util.stream.IntStream; 13 | 14 | @Singleton 15 | @Startup 16 | public class InitAppMB implements Serializable { 17 | 18 | @Inject 19 | @Service 20 | private CrudService crudService; 21 | 22 | @PostConstruct 23 | public void init() { 24 | IntStream.rangeClosed(1, 50) 25 | .forEach(i -> create(i)); 26 | } 27 | 28 | 29 | private void create(int i) { 30 | crudService.insert(new Car().model("model " + i).name("name" + i).price(Double.valueOf(i))); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/github/adminfaces/starter/bean/Lists.java: -------------------------------------------------------------------------------- 1 | package com.github.adminfaces.starter.bean; 2 | 3 | import com.github.adminfaces.persistence.service.CrudService; 4 | import com.github.adminfaces.persistence.service.Service; 5 | import com.github.adminfaces.starter.model.Car; 6 | import com.github.adminfaces.starter.model.Car_; 7 | 8 | import javax.enterprise.context.ApplicationScoped; 9 | import javax.enterprise.inject.Produces; 10 | import javax.inject.Inject; 11 | import javax.inject.Named; 12 | import java.io.Serializable; 13 | import java.util.List; 14 | 15 | @ApplicationScoped 16 | public class Lists implements Serializable { 17 | 18 | @Inject 19 | @Service 20 | private CrudService crudService; 21 | 22 | 23 | 24 | @Produces 25 | @Named("models") 26 | public List models() { 27 | return crudService.criteria() 28 | .select(String.class, crudService.attribute(Car_.model)) 29 | .getResultList(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/github/adminfaces/starter/infra/persistence/EntityManagerProducer.java: -------------------------------------------------------------------------------- 1 | package com.github.adminfaces.starter.infra.persistence; 2 | 3 | 4 | import javax.enterprise.context.ApplicationScoped; 5 | import javax.enterprise.inject.Produces; 6 | import javax.persistence.EntityManager; 7 | import javax.persistence.PersistenceContext; 8 | 9 | 10 | @ApplicationScoped 11 | public class EntityManagerProducer { 12 | 13 | @PersistenceContext 14 | EntityManager em; 15 | 16 | @Produces 17 | public EntityManager produce() { 18 | return em; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /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 javax.enterprise.context.SessionScoped; 7 | import javax.enterprise.inject.Specializes; 8 | import javax.inject.Named; 9 | import java.io.IOException; 10 | import java.io.Serializable; 11 | 12 | import static com.github.adminfaces.persistence.util.Messages.addDetailMessage; 13 | 14 | 15 | /** 16 | * Created by rmpestano on 12/20/14. 17 | * 18 | * This is just a login example. 19 | * 20 | * AdminSession uses isLoggedIn to determine if user must be redirect to login page or not. 21 | * By default AdminSession isLoggedIn always resolves to true so it will not try to redirect user. 22 | * 23 | * If you already have your authorization mechanism which controls when user must be redirect to initial page or logon 24 | * you can skip this class. 25 | */ 26 | @Named 27 | @SessionScoped 28 | @Specializes 29 | public class LogonMB extends AdminSession implements Serializable { 30 | 31 | private String currentUser; 32 | private String email; 33 | private String password; 34 | private boolean remember; 35 | 36 | 37 | public void login() throws IOException { 38 | currentUser = email; 39 | addDetailMessage("Logged in successfully as " + email + ""); 40 | Faces.getExternalContext().getFlash().setKeepMessages(true); 41 | Faces.redirect("index.xhtml"); 42 | } 43 | 44 | @Override 45 | public boolean isLoggedIn() { 46 | 47 | return currentUser != null; 48 | } 49 | 50 | public String getEmail() { 51 | return email; 52 | } 53 | 54 | public void setEmail(String email) { 55 | this.email = email; 56 | } 57 | 58 | public String getPassword() { 59 | return password; 60 | } 61 | 62 | public void setPassword(String password) { 63 | this.password = password; 64 | } 65 | 66 | public boolean isRemember() { 67 | return remember; 68 | } 69 | 70 | public void setRemember(boolean remember) { 71 | this.remember = remember; 72 | } 73 | 74 | public String getCurrentUser() { 75 | return currentUser; 76 | } 77 | 78 | public void setCurrentUser(String currentUser) { 79 | this.currentUser = currentUser; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /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 | 8 | 9 | import com.github.adminfaces.persistence.model.BaseEntity; 10 | import com.github.adminfaces.persistence.model.PersistenceEntity; 11 | 12 | import javax.persistence.*; 13 | 14 | /** 15 | * @author rmpestano 16 | */ 17 | @Entity 18 | @Table(name = "car") 19 | public class Car extends BaseEntity { 20 | 21 | @Id 22 | @GeneratedValue(strategy = GenerationType.AUTO) 23 | private Integer id; 24 | 25 | @Column(name = "model") 26 | private String model; 27 | 28 | @Column(name = "name") 29 | private String name; 30 | 31 | @Column(name = "price") 32 | private Double price; 33 | 34 | @Version 35 | private Integer version; 36 | 37 | public Car() { 38 | } 39 | 40 | public Car(Integer id) { 41 | this.id = id; 42 | } 43 | 44 | public String getModel() { 45 | return model; 46 | } 47 | 48 | public Double getPrice() { 49 | return price; 50 | } 51 | 52 | @Override 53 | public Integer getId() { 54 | return id; 55 | } 56 | 57 | public String getName() { 58 | return name; 59 | } 60 | 61 | public void setModel(String model) { 62 | this.model = model; 63 | } 64 | 65 | public void setName(String name) { 66 | this.name = name; 67 | } 68 | 69 | public void setPrice(Double price) { 70 | this.price = price; 71 | } 72 | 73 | public Integer getVersion() { 74 | return version; 75 | } 76 | 77 | public void setVersion(Integer version) { 78 | this.version = version; 79 | } 80 | 81 | public Car model(String model) { 82 | this.model = model; 83 | return this; 84 | } 85 | 86 | public Car price(Double price) { 87 | this.price = price; 88 | return this; 89 | } 90 | 91 | public Car name(String name) { 92 | this.name = name; 93 | return this; 94 | } 95 | 96 | public boolean hasModel() { 97 | return model != null && !"".equals(model.trim()); 98 | } 99 | 100 | public boolean hasName() { 101 | return name != null && !"".equals(name.trim()); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/github/adminfaces/starter/service/CarRepository.java: -------------------------------------------------------------------------------- 1 | package com.github.adminfaces.starter.service; 2 | 3 | import com.github.adminfaces.starter.model.Car; 4 | import org.apache.deltaspike.data.api.EntityRepository; 5 | import org.apache.deltaspike.data.api.Query; 6 | import org.apache.deltaspike.data.api.QueryParam; 7 | import org.apache.deltaspike.data.api.Repository; 8 | 9 | import java.math.BigDecimal; 10 | 11 | @Repository 12 | public interface CarRepository extends EntityRepository { 13 | 14 | 15 | @Query("SELECT SUM(c.price) FROM Car c WHERE upper(c.model) like :model") 16 | Double getTotalPriceByModel(@QueryParam("model") String model); 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /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.persistence.model.Filter; 8 | import com.github.adminfaces.persistence.service.CrudService; 9 | import com.github.adminfaces.starter.model.Car; 10 | import com.github.adminfaces.starter.model.Car_; 11 | import com.github.adminfaces.template.exception.BusinessException; 12 | import org.apache.deltaspike.data.api.criteria.Criteria; 13 | 14 | import javax.ejb.Stateless; 15 | import javax.inject.Inject; 16 | import java.io.Serializable; 17 | import java.util.List; 18 | 19 | import static com.github.adminfaces.template.util.Assert.has; 20 | 21 | /** 22 | * @author rmpestano 23 | */ 24 | @Stateless 25 | public class CarService extends CrudService implements Serializable { 26 | 27 | @Inject 28 | protected CarRepository carRepository;//you can create repositories to extract complex queries from your service 29 | 30 | 31 | protected Criteria configRestrictions(Filter filter) { 32 | 33 | Criteria criteria = criteria(); 34 | 35 | //create restrictions based on parameters map 36 | if (filter.hasParam("id")) { 37 | criteria.eq(Car_.id, filter.getIntParam("id")); 38 | } 39 | 40 | if (filter.hasParam("minPrice") && filter.hasParam("maxPrice")) { 41 | criteria.between(Car_.price, filter.getDoubleParam("minPrice"), filter.getDoubleParam("maxPrice")); 42 | } else if (filter.hasParam("minPrice")) { 43 | criteria.gtOrEq(Car_.price, filter.getDoubleParam("minPrice")); 44 | } else if (filter.hasParam("maxPrice")) { 45 | criteria.ltOrEq(Car_.price, filter.getDoubleParam("maxPrice")); 46 | } 47 | 48 | //create restrictions based on filter entity 49 | if (has(filter.getEntity())) { 50 | Car filterEntity = filter.getEntity(); 51 | if (has(filterEntity.getModel())) { 52 | criteria.likeIgnoreCase(Car_.model, "%" + filterEntity.getModel()); 53 | } 54 | 55 | if (has(filterEntity.getPrice())) { 56 | criteria.eq(Car_.price, filterEntity.getPrice()); 57 | } 58 | 59 | if (has(filterEntity.getName())) { 60 | criteria.likeIgnoreCase(Car_.name, "%" + filterEntity.getName() + "%"); 61 | } 62 | } 63 | return criteria; 64 | } 65 | 66 | public void beforeInsert(Car car) { 67 | validate(car); 68 | } 69 | 70 | public void beforeUpdate(Car car) { 71 | validate(car); 72 | } 73 | 74 | public void validate(Car car) { 75 | BusinessException be = new BusinessException(); 76 | if (!car.hasModel()) { 77 | be.addException(new BusinessException("Car model cannot be empty")); 78 | } 79 | if (!car.hasName()) { 80 | be.addException(new BusinessException("Car name cannot be empty")); 81 | } 82 | 83 | if (!has(car.getPrice())) { 84 | be.addException(new BusinessException("Car price cannot be empty")); 85 | } 86 | 87 | if (count(criteria() 88 | .eqIgnoreCase(Car_.name, car.getName()) 89 | .notEq(Car_.id, car.getId())) > 0) { 90 | 91 | be.addException(new BusinessException("Car name must be unique")); 92 | } 93 | 94 | if (has(be.getExceptionList())) { 95 | throw be; 96 | } 97 | } 98 | 99 | 100 | public List listByModel(String model) { 101 | return criteria() 102 | .likeIgnoreCase(Car_.model, model) 103 | .getResultList(); 104 | } 105 | 106 | public List getModels(String query) { 107 | return criteria() 108 | .select(String.class, attribute(Car_.model)) 109 | .likeIgnoreCase(Car_.model, "%" + query + "%") 110 | .getResultList(); 111 | } 112 | 113 | public Double getTotalPriceByModel(Car car) { 114 | if (!has(car.hasModel())) { 115 | throw new BusinessException("Provide car model to get the total price."); 116 | } 117 | return carRepository.getTotalPriceByModel(car.getModel().toUpperCase()); 118 | } 119 | 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/apache-deltaspike.properties: -------------------------------------------------------------------------------- 1 | globalAlternatives.org.apache.deltaspike.jpa.spi.transaction.TransactionStrategy = org.apache.deltaspike.jpa.impl.transaction.ContainerManagedTransactionStrategy -------------------------------------------------------------------------------- /src/main/resources/META-INF/persistence.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | java:comp/DefaultDataSource 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/main/resources/admin-config.properties: -------------------------------------------------------------------------------- 1 | admin.renderControlSidebar=true 2 | admin.controlSidebar.showOnMobile=true 3 | -------------------------------------------------------------------------------- /src/main/resources/messages.properties: -------------------------------------------------------------------------------- 1 | starter.version=${project.version} 2 | 3 | label.model= Model 4 | label.name= Name 5 | label.minPrice=Min price 6 | label.maxPrice=Max price -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | org.apache.deltaspike.jpa.impl.transaction.BeanManagedUserTransactionStrategy 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/faces-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | org.omnifaces.resourcehandler.CombinedResourceHandler 9 | messages 10 | 11 | messages 12 | msg 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /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/WEB-INF/jboss-web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | /admin-starter 4 | 5 | -------------------------------------------------------------------------------- /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 | 23 | Admin Starter 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
  • 37 |
  • 38 |
    39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 48 | Copyright (C) 2017-2018 - AdminFaces Starter Project 49 | 50 | 51 | 54 | 55 | 56 | 57 | 58 |
    -------------------------------------------------------------------------------- /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 | 23 | Admin Starter 24 | 25 | 26 | 27 | Admin 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-2018 - AdminFaces Starter Project 52 | 53 | 54 | 57 | 58 | 59 | 60 | 61 |
    -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 30 7 | 8 | 9 | 10 | javax.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 | com.sun.faces.numberOfLogicalViews 27 | 6 28 | 29 | 30 | com.sun.faces.numberOfViewsInSession 31 | 6 32 | 33 | 34 | org.omnifaces.VIEW_SCOPE_MANAGER_MAX_ACTIVE_VIEW_SCOPES 35 | 6 36 | 37 | 38 | javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL 39 | true 40 | 41 | 42 | index.html 43 | 44 | 45 | Faces Servlet 46 | javax.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 | *.xhtml 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /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 | 46 | 49 | 52 | 54 | 56 | 57 | 58 | 59 | 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 |
    114 | 117 | 120 | 122 | 124 | 125 | 126 | 127 | 130 | 131 |
    132 |
    133 | 134 | 135 | 137 | 139 | 140 |
    141 | 142 | 143 |
    144 | 145 |
    146 | -------------------------------------------------------------------------------- /src/main/webapp/car-list.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 36 | 37 | 38 | 39 | Find cars by name, price and model 40 | 41 | 42 | 43 | 44 | 45 | 46 |
    47 |
    48 | 68 | 69 | 72 | 76 | 77 | 78 | 81 | 82 | 85 | 86 | 87 | 88 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | Find Car by id: 105 | 106 | 112 | 113 | 114 | 115 | 117 | 118 | 121 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | #{c.name} 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | #{c.price} 146 | 147 | 148 | 151 | 152 | 153 |
    154 |
    155 | 156 | 158 | 160 | 161 |
    162 | 163 | 164 | 166 | 167 | 168 | 170 | 171 | 174 | 175 | 176 | 177 | 178 |
    179 |
    180 | 181 |
    182 |
    183 | 184 | 185 | 187 | 188 |
    189 |
    190 | 191 |
    192 |
    193 | 194 |
    195 | 196 |
    197 |
    198 | 199 |
    200 |
    201 | 202 |
    203 |
    204 | 205 |
    206 |
    207 | 208 |
    209 |
    210 | 211 |
    212 |
    213 |
    214 |
    215 |
    216 | 217 | 218 | 219 | 222 | 223 | 224 |
    225 | 226 |
    227 | -------------------------------------------------------------------------------- /src/main/webapp/includes/controlsidebar-tabs-content.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 110 | 111 |
    112 |
    113 |

    General Settings

    114 | 115 |
    116 | 120 | 121 |

    122 | Some information about this general settings option 123 |

    124 |
    125 | 126 |
    127 | 131 | 132 |

    133 | Other sets of options are available 134 |

    135 |
    136 | 137 |
    138 | 142 | 143 |

    144 | Allow the user to show his name in blog posts 145 |

    146 |
    147 | 148 |

    Chat Settings

    149 | 150 |
    151 | 155 |
    156 | 157 |
    158 | 162 |
    163 | 164 |
    165 | 170 |
    171 |
    172 |
    173 | 174 |
    -------------------------------------------------------------------------------- /src/main/webapp/includes/menu.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 24 | 25 | -------------------------------------------------------------------------------- /src/main/webapp/includes/menubar.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/main/webapp/includes/top-bar.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 17 | 63 | 64 | -------------------------------------------------------------------------------- /src/main/webapp/index.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

    13 | Welcome to the AdminFaces Starter Project! 16 |
    17 | Integrating , and 19 | into your 20 | application. 21 | 22 |

    23 | 24 |
    25 | 26 |
    27 | -------------------------------------------------------------------------------- /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 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 76 | 77 | 79 | 80 | 81 | 82 | 133 | 134 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /src/main/webapp/public/index.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

    13 | Welcome to the AdminFaces Starter Project! 16 |
    17 | Integrating , and 19 | into your 20 | application. 21 | 22 |

    23 | 24 |
    25 | 26 |
    27 | -------------------------------------------------------------------------------- /src/main/webapp/resources/css/starter.css: -------------------------------------------------------------------------------- 1 | li.header { 2 | text-transform: uppercase; 3 | } 4 | 5 | .sidebar-form { 6 | border-radius: 3px; 7 | border: 1px solid #374850; 8 | margin: 10px 10px; 9 | } 10 | .sidebar-form, .sidebar-menu>li.header { 11 | overflow: hidden; 12 | text-overflow: clip; 13 | } 14 | 15 | #userImage { 16 | float: left; 17 | width: 25px; 18 | height: 25px; 19 | border-radius: 50%; 20 | margin-right: 10px; 21 | margin-top: -2px; 22 | } 23 | 24 | ul.dropdown-menu > li.user-header { 25 | height: auto!important; 26 | } 27 | 28 | a.dropdown-toggle { 29 | background-color: #3c8dbc!important; 30 | } 31 | 32 | a#logout { 33 | color: #3c8dbc!important; 34 | background: transparent; 35 | } -------------------------------------------------------------------------------- /src/main/webapp/resources/favicon/favicon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter-persistence/98b86adbf83bb32433381a613c2d03f8d5612c9a/src/main/webapp/resources/favicon/favicon-144x144.png -------------------------------------------------------------------------------- /src/main/webapp/resources/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter-persistence/98b86adbf83bb32433381a613c2d03f8d5612c9a/src/main/webapp/resources/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /src/main/webapp/resources/favicon/favicon-196x196.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter-persistence/98b86adbf83bb32433381a613c2d03f8d5612c9a/src/main/webapp/resources/favicon/favicon-196x196.png -------------------------------------------------------------------------------- /src/main/webapp/resources/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter-persistence/98b86adbf83bb32433381a613c2d03f8d5612c9a/src/main/webapp/resources/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /src/main/webapp/resources/favicon/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter-persistence/98b86adbf83bb32433381a613c2d03f8d5612c9a/src/main/webapp/resources/favicon/favicon-96x96.png -------------------------------------------------------------------------------- /src/main/webapp/resources/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter-persistence/98b86adbf83bb32433381a613c2d03f8d5612c9a/src/main/webapp/resources/favicon/favicon.ico -------------------------------------------------------------------------------- /src/main/webapp/resources/images/login-bg-mobile.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter-persistence/98b86adbf83bb32433381a613c2d03f8d5612c9a/src/main/webapp/resources/images/login-bg-mobile.jpeg -------------------------------------------------------------------------------- /src/main/webapp/resources/images/login-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter-persistence/98b86adbf83bb32433381a613c2d03f8d5612c9a/src/main/webapp/resources/images/login-bg.jpg -------------------------------------------------------------------------------- /src/test/java/com/github/adminfaces/ft/AdminFt.java: -------------------------------------------------------------------------------- 1 | package com.github.adminfaces.ft; 2 | 3 | import static org.assertj.core.api.Java6Assertions.assertThat; 4 | import static org.jboss.arquillian.graphene.Graphene.guardHttp; 5 | import static org.jboss.arquillian.graphene.Graphene.waitGui; 6 | import static org.jboss.arquillian.graphene.Graphene.waitModel; 7 | import static org.junit.Assert.assertTrue; 8 | 9 | import java.net.URL; 10 | import java.util.concurrent.TimeUnit; 11 | 12 | import org.jboss.arquillian.container.test.api.Deployment; 13 | import org.jboss.arquillian.drone.api.annotation.Drone; 14 | import org.jboss.arquillian.graphene.GrapheneElement; 15 | import org.jboss.arquillian.graphene.findby.FindByJQuery; 16 | import org.jboss.arquillian.graphene.page.InitialPage; 17 | import org.jboss.arquillian.graphene.page.Page; 18 | import org.jboss.arquillian.junit.Arquillian; 19 | import org.jboss.arquillian.junit.InSequence; 20 | import org.jboss.arquillian.test.api.ArquillianResource; 21 | import org.jboss.shrinkwrap.api.Archive; 22 | import org.jboss.shrinkwrap.api.Filters; 23 | import org.jboss.shrinkwrap.api.GenericArchive; 24 | import org.jboss.shrinkwrap.api.ShrinkWrap; 25 | import org.jboss.shrinkwrap.api.importer.ExplodedImporter; 26 | import org.jboss.shrinkwrap.api.spec.WebArchive; 27 | import org.jboss.shrinkwrap.resolver.api.maven.Maven; 28 | import org.jboss.shrinkwrap.resolver.api.maven.MavenResolverSystem; 29 | import org.junit.Test; 30 | import org.junit.runner.RunWith; 31 | import org.openqa.selenium.By; 32 | import org.openqa.selenium.WebDriver; 33 | import org.openqa.selenium.interactions.Actions; 34 | 35 | import com.github.adminfaces.ft.pages.CarFormPage; 36 | import com.github.adminfaces.ft.pages.CarListPage; 37 | import com.github.adminfaces.ft.pages.IndexPage; 38 | import com.github.adminfaces.ft.pages.LogonPage; 39 | import com.github.adminfaces.ft.pages.fragments.LeftMenu; 40 | import com.github.adminfaces.ft.pages.fragments.SearchDialog; 41 | import com.github.adminfaces.util.Deployments; 42 | import org.junit.Ignore; 43 | 44 | /** 45 | * Car acceptance tests 46 | */ 47 | 48 | @RunWith(Arquillian.class) 49 | public class AdminFt { 50 | 51 | @Deployment(name = "admin-starter-ft.war", testable = false) 52 | public static Archive createDeployment() { 53 | WebArchive war = Deployments.createDeployment(); 54 | MavenResolverSystem resolver = Maven.resolver(); 55 | war.addAsLibraries(resolver.loadPomFromFile("pom.xml").resolve("com.github.adminfaces:admin-template").withTransitivity().asFile()); 56 | war.merge(ShrinkWrap.create(GenericArchive.class).as(ExplodedImporter.class).importDirectory("src/main/webapp").as(GenericArchive.class), "/", Filters.include(".*\\.(xml|xhtml|html|css|js|png|jpg|gif)$")); 57 | System.out.println(war.toString(true)); 58 | return war; 59 | } 60 | 61 | @ArquillianResource 62 | URL url; 63 | 64 | @Drone 65 | WebDriver webDriver; 66 | 67 | @FindByJQuery("div[id='messages'] span.ui-messages-error-detail") 68 | private GrapheneElement errorMessages; 69 | 70 | @FindByJQuery("div[id='info-messages'] .ui-messages-info-detail") 71 | private GrapheneElement infoMessages; 72 | 73 | 74 | @Page 75 | private LogonPage logon; 76 | 77 | @Page 78 | private IndexPage index; 79 | 80 | @Page 81 | private CarListPage carList; 82 | 83 | @Page 84 | private CarFormPage carForm; 85 | 86 | @FindByJQuery("section.sidebar > ul.sidebar-menu") 87 | private LeftMenu menu; 88 | 89 | @FindByJQuery("div.ui-dialog.box-success") 90 | private SearchDialog searchDialog; 91 | 92 | 93 | @Test 94 | @InSequence(1) 95 | public void shouldLogonSuccessfully(@InitialPage LogonPage logon) { 96 | assertThat(logon.isPresent()).isTrue(); 97 | logon.doLogon("abc@gmail.com", "abcde"); 98 | assertThat(infoMessages.isPresent()).isTrue(); 99 | assertThat(infoMessages.getText()).contains("Logged in successfully as abc@gmail.com"); 100 | } 101 | 102 | @Test 103 | @InSequence(2) 104 | public void shouldListCars() { 105 | menu.listCars(); 106 | assertThat(carList.isPresent()).isTrue(); 107 | } 108 | 109 | @Test 110 | @InSequence(3) 111 | public void shouldPaginateCars() { 112 | carList.paginate(); 113 | carList.getDatatable().findGrapheneElements(By.cssSelector("a.ui-link")) 114 | .forEach(e -> assertTrue(e.getText().equals("model 46") || 115 | e.getText().equals("model 47") || e.getText().equals("model 48") 116 | || e.getText().equals("model 49") || e.getText().equals("model 50"))); 117 | } 118 | 119 | 120 | @Test 121 | @InSequence(4) 122 | public void shouldFilterByModel() { 123 | carList.filterByModel("model 8"); 124 | waitModel(webDriver).until().element(By.cssSelector("ul.ui-autocomplete-items")).is().not().visible(); 125 | assertThat(carList.getTableRows().get(0).getText()).contains("model 8"); 126 | } 127 | 128 | @Test 129 | @InSequence(5) 130 | public void shouldRemoveMultipleCars() { 131 | waitModel(webDriver); 132 | carList.clear(); 133 | waitModel(webDriver).until().element(By.cssSelector("div.ui-dialog-content img")) 134 | .is().not().visible(); 135 | webDriver.findElements(By.cssSelector("td .ui-chkbox-box")).forEach(e -> { 136 | Actions actions = new Actions(webDriver); 137 | actions.moveToElement(e).click().perform(); 138 | waitModel(); 139 | } 140 | ); 141 | waitModel(webDriver).until().element(By.cssSelector("div.ui-dialog-content img")) 142 | .is().not().visible(); 143 | carList.remove(); 144 | assertThat(infoMessages.getText()).contains("cars deleted successfully!"); 145 | } 146 | 147 | @Test 148 | @InSequence(6) 149 | public void shouldEditViaDatatable() { 150 | waitModel().withTimeout(5,TimeUnit.SECONDS).until() 151 | .element(carList.getConfirmHeader()).is().not().visible(); 152 | carList.filterByModel("model 20"); 153 | waitModel(webDriver).until().element(By.cssSelector("ul.ui-autocomplete-items")).is().not().visible(); 154 | guardHttp(webDriver.findElement(By.cssSelector("td[role=gridcell] a"))).click(); 155 | assertThat(carForm.isPresent()).isTrue(); 156 | carForm.getInputModel().clear(); 157 | waitGui(webDriver); 158 | carForm.getInputModel().sendKeys("model edit"); 159 | carForm.save(); 160 | assertThat(infoMessages.getText()).isEqualTo("Car model edit updated successfully"); 161 | } 162 | 163 | @Test 164 | @InSequence(7) 165 | public void shouldEditViaUrl() { 166 | menu.goHome(); 167 | webDriver.get(url+"/car-form.xhtml?id=20"); 168 | assertThat(carForm.isPresent()).isTrue(); 169 | carForm.getInputModel().clear(); 170 | waitGui(webDriver); 171 | carForm.getInputModel().sendKeys("model 20 edit"); 172 | carForm.save(); 173 | assertThat(infoMessages.getText()).isEqualTo("Car model 20 edit updated successfully"); 174 | } 175 | 176 | @Test 177 | @InSequence(8) 178 | //@Ignore("yes button from confirm dialog is not enabled") 179 | public void shouldRemoveCar() { 180 | waitModel(webDriver); 181 | carForm.remove(); 182 | waitModel(webDriver).until().element(infoMessages).is().present(); 183 | assertThat(infoMessages.getText()).isEqualTo("Car model 20 edit removed successfully"); 184 | } 185 | 186 | @Test 187 | @InSequence(9) 188 | public void shouldInsertCar(@InitialPage CarListPage carList) { 189 | carList.newCar(); 190 | waitModel().until().element(carForm.getInputModel()).is().present(); 191 | carForm.getInputModel().sendKeys("new model"); 192 | carForm.getInputName().sendKeys("new name"); 193 | carForm.getInputPrice().sendKeys("1.5"); 194 | carForm.save(); 195 | assertThat(infoMessages.getText()).isEqualTo("Car new model created successfully"); 196 | } 197 | 198 | @Test 199 | @InSequence(10) 200 | public void shouldSearchCarByNameAndPrice(@InitialPage CarListPage carList) { 201 | carList.search(); 202 | searchDialog.getName().sendKeys("name1"); 203 | searchDialog.getMinPrice().sendKeys("16"); 204 | searchDialog.getMaxPrice().sendKeys("17.8"); 205 | searchDialog.search(); 206 | searchDialog.close(); 207 | assertThat(carList.getTableRows()).hasSize(2); 208 | assertThat(carList.getTableRows().get(0).getText()).contains("name16"); 209 | assertThat(carList.getTableRows().get(1).getText()).contains("name17"); 210 | 211 | } 212 | 213 | @Test 214 | @InSequence(99) 215 | public void shouldLogout() { 216 | webDriver.findElement(By.id("userImage")).click(); 217 | waitModel().until().element(By.cssSelector("li.open")).is().present(); 218 | webDriver.findElement(By.id("logout")).click(); 219 | waitModel().until().element(logon.getLoginBox()).is().present(); 220 | assertThat(webDriver.findElement(By.className("login-logo")).isDisplayed()).isTrue(); 221 | } 222 | 223 | 224 | } 225 | -------------------------------------------------------------------------------- /src/test/java/com/github/adminfaces/ft/pages/CarFormPage.java: -------------------------------------------------------------------------------- 1 | package com.github.adminfaces.ft.pages; 2 | 3 | import org.jboss.arquillian.drone.api.annotation.Drone; 4 | import org.jboss.arquillian.graphene.GrapheneElement; 5 | import org.jboss.arquillian.graphene.findby.FindByJQuery; 6 | import org.jboss.arquillian.graphene.page.Location; 7 | import org.openqa.selenium.By; 8 | import org.openqa.selenium.WebDriver; 9 | 10 | import static org.jboss.arquillian.graphene.Graphene.guardAjax; 11 | import static org.jboss.arquillian.graphene.Graphene.waitModel; 12 | 13 | @Location("login.xhtml") 14 | public class CarFormPage { 15 | 16 | @FindByJQuery("section.content-header h1") 17 | private GrapheneElement header; 18 | 19 | @FindByJQuery("input[id$=inptModel]") 20 | private GrapheneElement inputModel; 21 | 22 | @FindByJQuery("input[id$=inptName]") 23 | private GrapheneElement inputName; 24 | 25 | @FindByJQuery("input[id$=inptPrice_input]") 26 | private GrapheneElement inputPrice; 27 | 28 | @FindByJQuery("button[id$=brFind]") 29 | private GrapheneElement btFind; 30 | 31 | @FindByJQuery("button.btn-danger") 32 | private GrapheneElement btRemove; 33 | 34 | @FindByJQuery("button.btn-primary") 35 | private GrapheneElement btSave; 36 | 37 | @FindByJQuery("span.ui-button-text:contains('Yes')") 38 | private GrapheneElement btYes; 39 | 40 | @FindByJQuery("span.ui-dialog-title:contains('Confirmation')") 41 | private GrapheneElement confirmHeader; 42 | 43 | @Drone 44 | private WebDriver browser; 45 | 46 | public boolean isPresent() { 47 | return header.isPresent() && header.getText().contains("Car form"); 48 | } 49 | 50 | 51 | public GrapheneElement getInputModel() { 52 | return inputModel; 53 | } 54 | 55 | public GrapheneElement getInputName() { 56 | return inputName; 57 | } 58 | 59 | public GrapheneElement getInputPrice() { 60 | return inputPrice; 61 | } 62 | 63 | public void save() { 64 | guardAjax(btSave).click(); 65 | } 66 | 67 | public void remove() { 68 | btRemove.click(); 69 | waitModel().until().element(confirmHeader).is().present(); 70 | guardAjax(btYes).click(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/test/java/com/github/adminfaces/ft/pages/CarListPage.java: -------------------------------------------------------------------------------- 1 | package com.github.adminfaces.ft.pages; 2 | 3 | import org.jboss.arquillian.drone.api.annotation.Drone; 4 | import org.jboss.arquillian.graphene.GrapheneElement; 5 | import org.jboss.arquillian.graphene.findby.FindByJQuery; 6 | import org.jboss.arquillian.graphene.page.Location; 7 | import org.openqa.selenium.By; 8 | import org.openqa.selenium.WebDriver; 9 | import org.openqa.selenium.WebElement; 10 | 11 | import java.util.List; 12 | 13 | import static org.jboss.arquillian.graphene.Graphene.guardAjax; 14 | import static org.jboss.arquillian.graphene.Graphene.waitModel; 15 | 16 | @Location("car-list.xhtml") 17 | public class CarListPage { 18 | 19 | @FindByJQuery("button.btn-primary") 20 | private GrapheneElement btNew; 21 | 22 | @FindByJQuery("button.btn-info") 23 | private GrapheneElement btSearch; 24 | 25 | @FindByJQuery("span.ui-button-text:contains('Delete')") 26 | private GrapheneElement btRemove; 27 | 28 | @FindByJQuery("span.ui-button-text:contains('Clear')") 29 | private GrapheneElement btClear; 30 | 31 | @FindByJQuery("span.ui-button-text:contains('Yes')") 32 | private GrapheneElement btYes; 33 | 34 | @FindByJQuery("section.content-header h1") 35 | private GrapheneElement header; 36 | 37 | @FindByJQuery("hr.ui-separator + div.ui-datatable") 38 | private GrapheneElement datatable; 39 | 40 | @FindByJQuery("hr.ui-separator + div.ui-datatable tbody tr") 41 | private List datatableRows; 42 | 43 | @FindByJQuery("a.ui-paginator-page[aria-label='Page 10']") 44 | private GrapheneElement page10; 45 | 46 | @FindByJQuery("button.ui-autocomplete-dropdown") 47 | private GrapheneElement modelAutocompleteButton; 48 | 49 | @FindByJQuery(".ui-column-customfilter span.ui-autocomplete > input") 50 | private GrapheneElement datatableModelFilter; 51 | 52 | @FindByJQuery("ul.ui-autocomplete-items") 53 | private GrapheneElement modelFilterCompleteItens; 54 | 55 | @FindByJQuery("span.ui-dialog-title:contains('Confirmation')") 56 | private GrapheneElement confirmHeader; 57 | 58 | @Drone 59 | private WebDriver browser; 60 | 61 | public boolean isPresent() { 62 | return header.isPresent() && header.getText().contains("Car listing Find cars by name, price and model"); 63 | } 64 | 65 | public void paginate() { 66 | guardAjax(page10).click(); 67 | } 68 | 69 | public GrapheneElement getDatatable() { 70 | return datatable; 71 | } 72 | 73 | public void filterByModel(String filterCriteria) { 74 | datatableModelFilter.click(); 75 | datatableModelFilter.sendKeys(filterCriteria); 76 | waitModel().until().element(modelFilterCompleteItens) 77 | .is().present(); 78 | guardAjax(modelFilterCompleteItens.findElement(By.cssSelector("li.ui-autocomplete-item[data-item-value='" + 79 | "" + filterCriteria +"']"))).click(); 80 | } 81 | 82 | public List getTableRows(){ 83 | return browser.findElements(By.cssSelector("hr.ui-separator + div.ui-datatable tbody tr")); 84 | } 85 | 86 | public GrapheneElement getConfirmHeader() { 87 | return confirmHeader; 88 | } 89 | 90 | public GrapheneElement getDatatableModelFilter() { 91 | return datatableModelFilter; 92 | } 93 | 94 | public void newCar(){ 95 | btNew.click(); 96 | } 97 | 98 | public void clear() { 99 | guardAjax(btClear).click(); 100 | } 101 | 102 | public void search() { 103 | guardAjax(btSearch).click(); 104 | } 105 | 106 | public void remove() { 107 | btRemove.click(); 108 | waitModel().until().element(confirmHeader).is().present(); 109 | guardAjax(btYes).click(); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/test/java/com/github/adminfaces/ft/pages/IndexPage.java: -------------------------------------------------------------------------------- 1 | package com.github.adminfaces.ft.pages; 2 | 3 | import org.jboss.arquillian.graphene.GrapheneElement; 4 | import org.jboss.arquillian.graphene.findby.FindByJQuery; 5 | import org.jboss.arquillian.graphene.page.Location; 6 | 7 | import static org.jboss.arquillian.graphene.Graphene.guardAjax; 8 | 9 | @Location("index.xhtml") 10 | public class IndexPage { 11 | 12 | @FindByJQuery("H2") 13 | private GrapheneElement title; 14 | 15 | 16 | public GrapheneElement getTitle() { 17 | return title; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/com/github/adminfaces/ft/pages/LogonPage.java: -------------------------------------------------------------------------------- 1 | package com.github.adminfaces.ft.pages; 2 | 3 | import org.jboss.arquillian.graphene.GrapheneElement; 4 | import org.jboss.arquillian.graphene.findby.FindByJQuery; 5 | import org.jboss.arquillian.graphene.fragment.Root; 6 | import org.jboss.arquillian.graphene.page.Location; 7 | 8 | import static org.jboss.arquillian.graphene.Graphene.guardAjax; 9 | import static org.jboss.arquillian.graphene.Graphene.guardHttp; 10 | import static org.jboss.arquillian.graphene.Graphene.waitModel; 11 | 12 | @Location("login.xhtml") 13 | public class LogonPage { 14 | 15 | 16 | @FindByJQuery("input[type=email]") 17 | private GrapheneElement email; 18 | 19 | @FindByJQuery("input[type=password]") 20 | private GrapheneElement password; 21 | 22 | @FindByJQuery("button.btn-success") 23 | private GrapheneElement btLogon; 24 | 25 | @FindByJQuery("div.login-box") 26 | private GrapheneElement loginBox; 27 | 28 | 29 | public void doLogon(String email, String password) { 30 | waitModel(); 31 | this.email.clear(); 32 | this.email.sendKeys(email); 33 | this.password.clear(); 34 | this.password.sendKeys(password); 35 | guardAjax(btLogon).click(); 36 | } 37 | 38 | public boolean isPresent() { 39 | return loginBox.isPresent(); 40 | } 41 | 42 | public GrapheneElement getLoginBox() { 43 | return loginBox; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/com/github/adminfaces/ft/pages/fragments/LeftMenu.java: -------------------------------------------------------------------------------- 1 | package com.github.adminfaces.ft.pages.fragments; 2 | 3 | import org.jboss.arquillian.graphene.GrapheneElement; 4 | import org.jboss.arquillian.graphene.findby.FindByJQuery; 5 | import org.jboss.arquillian.graphene.fragment.Root; 6 | 7 | import static org.jboss.arquillian.graphene.Graphene.guardHttp; 8 | 9 | public class LeftMenu { 10 | 11 | @Root 12 | private GrapheneElement menu; 13 | 14 | @FindByJQuery("li > a > i.fa-home") 15 | private GrapheneElement homeMenu; 16 | 17 | @FindByJQuery("li > a > i.fa-car") 18 | private GrapheneElement listCarMenu; 19 | 20 | public void listCars() { 21 | guardHttp(listCarMenu).click(); 22 | } 23 | 24 | public void goHome() { 25 | guardHttp(homeMenu).click(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/github/adminfaces/ft/pages/fragments/SearchDialog.java: -------------------------------------------------------------------------------- 1 | package com.github.adminfaces.ft.pages.fragments; 2 | 3 | import org.jboss.arquillian.graphene.GrapheneElement; 4 | import org.jboss.arquillian.graphene.findby.FindByJQuery; 5 | import org.jboss.arquillian.graphene.fragment.Root; 6 | 7 | import static org.jboss.arquillian.graphene.Graphene.guardAjax; 8 | import static org.jboss.arquillian.graphene.Graphene.guardHttp; 9 | 10 | public class SearchDialog { 11 | 12 | @Root 13 | private GrapheneElement dialog; 14 | 15 | @FindByJQuery("span.ui-dialog-title") 16 | private GrapheneElement title; 17 | 18 | @FindByJQuery("input[id$=name]") 19 | private GrapheneElement name; 20 | 21 | @FindByJQuery("input[id$=min_input]") 22 | private GrapheneElement minPrice; 23 | 24 | @FindByJQuery("input[id$=max_input]") 25 | private GrapheneElement maxPrice; 26 | 27 | @FindByJQuery("span.fa-close") 28 | private GrapheneElement btClose; 29 | 30 | @FindByJQuery("div.ui-dialog-content button.btn-primary") 31 | private GrapheneElement btOk; 32 | 33 | 34 | 35 | public void close() { 36 | guardAjax(btClose).click(); 37 | } 38 | 39 | public GrapheneElement getName() { 40 | return name; 41 | } 42 | 43 | public GrapheneElement getMinPrice() { 44 | return minPrice; 45 | } 46 | 47 | public GrapheneElement getMaxPrice() { 48 | return maxPrice; 49 | } 50 | 51 | public void search() { 52 | guardAjax(btOk).click(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/com/github/adminfaces/it/AdminIt.java: -------------------------------------------------------------------------------- 1 | package com.github.adminfaces.it; 2 | 3 | import com.github.adminfaces.persistence.model.AdminSort; 4 | import com.github.adminfaces.persistence.model.Filter; 5 | import com.github.adminfaces.persistence.service.CrudService; 6 | import com.github.adminfaces.persistence.service.Service; 7 | import com.github.adminfaces.starter.model.Car; 8 | import com.github.adminfaces.starter.model.Car_; 9 | import com.github.adminfaces.starter.service.CarService; 10 | import com.github.adminfaces.template.exception.BusinessException; 11 | import com.github.adminfaces.util.Deployments; 12 | import org.jboss.arquillian.container.test.api.Deployment; 13 | import org.jboss.arquillian.junit.Arquillian; 14 | import org.jboss.arquillian.persistence.Cleanup; 15 | import org.jboss.arquillian.persistence.TestExecutionPhase; 16 | import org.jboss.arquillian.persistence.UsingDataSet; 17 | import org.jboss.arquillian.transaction.api.annotation.TransactionMode; 18 | import org.jboss.arquillian.transaction.api.annotation.Transactional; 19 | import org.jboss.shrinkwrap.api.spec.WebArchive; 20 | import org.jboss.shrinkwrap.resolver.api.maven.Maven; 21 | import org.jboss.shrinkwrap.resolver.api.maven.MavenResolverSystem; 22 | import org.junit.Test; 23 | import org.junit.runner.RunWith; 24 | 25 | import javax.inject.Inject; 26 | import java.util.List; 27 | 28 | import static org.assertj.core.api.AssertionsForClassTypes.tuple; 29 | import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; 30 | import static org.junit.Assert.*; 31 | 32 | @RunWith(Arquillian.class) 33 | public class AdminIt { 34 | 35 | 36 | @Deployment(name = "admin-starter-it.war",testable = true) 37 | public static WebArchive createDeployment() { 38 | WebArchive war = Deployments.createDeployment(); 39 | MavenResolverSystem resolver = Maven.resolver(); 40 | war.addAsLibraries(resolver.loadPomFromFile("pom.xml").resolve("org.assertj:assertj-core").withTransitivity().asFile()); 41 | System.out.println(war.toString(true)); 42 | return war; 43 | } 44 | 45 | @Inject 46 | CarService carService; 47 | 48 | @Inject 49 | @Service 50 | CrudService crudService; 51 | 52 | 53 | @Test 54 | @UsingDataSet("cars.yml") 55 | public void shouldCountCars() { 56 | assertEquals(carService.count().intValue(), 4); 57 | } 58 | 59 | @Test 60 | @UsingDataSet("cars.yml") 61 | public void shouldFindCarById() { 62 | Car car = carService.findById(1); 63 | assertThat(car).isNotNull() 64 | .extracting("id") 65 | .contains(new Integer(1)); 66 | } 67 | 68 | @Test 69 | @UsingDataSet("cars.yml") 70 | public void shouldFindCarByExample() { 71 | Car carExample = new Car().model("Ferrari"); 72 | List cars = carService.example(carExample,Car_.model).getResultList(); 73 | assertThat(cars).isNotNull() 74 | .hasSize(1) 75 | .extracting("id") 76 | .contains(new Integer(1)); 77 | } 78 | 79 | @Test 80 | @Cleanup(phase = TestExecutionPhase.BEFORE) 81 | public void shouldNotInsertCarWithoutName() { 82 | long countBefore = carService.count(); 83 | assertEquals(countBefore, 0); 84 | Car newCar = new Car().model("My Car").price(1d); 85 | try { 86 | carService.insert(newCar); 87 | } catch (BusinessException e) { 88 | assertEquals("Car name cannot be empty", e.getExceptionList().get(0).getMessage()); 89 | } 90 | } 91 | 92 | @Test 93 | public void shouldNotInsertCarWithoutModel() { 94 | Car newCar = new Car().name("My Car") 95 | .price(1d); 96 | try { 97 | carService.insert(newCar); 98 | } catch (BusinessException e) { 99 | assertEquals("Car model cannot be empty", e.getExceptionList().get(0).getMessage()); 100 | } 101 | } 102 | 103 | @Test 104 | @UsingDataSet("cars.yml") 105 | @Cleanup(phase = TestExecutionPhase.BEFORE) 106 | public void shouldNotInsertCarWithDuplicateName() { 107 | Car newCar = new Car().model("My Car") 108 | .name("ferrari spider") 109 | .price(1d); 110 | try { 111 | carService.insert(newCar); 112 | } catch (BusinessException e) { 113 | assertEquals("Car name must be unique", e.getExceptionList().get(0).getMessage()); 114 | } 115 | } 116 | 117 | @Test 118 | public void shouldInsertCar() { 119 | long countBefore = carService.count(); 120 | assertEquals(countBefore, 0); 121 | Car newCar = new Car().model("My Car") 122 | .name("car name").price(1d); 123 | carService.insert(newCar); 124 | assertEquals(countBefore + 1, carService.count().intValue()); 125 | } 126 | 127 | @Test 128 | @UsingDataSet("cars.yml") 129 | @Transactional(TransactionMode.DISABLED) 130 | public void shouldRemoveCar() { 131 | assertEquals(carService.count(carService.criteria().eq(Car_.id,1)).intValue(),1); 132 | Car car = carService.findById(1); 133 | assertNotNull(car); 134 | carService.remove(car); 135 | assertEquals(carService.count(carService.criteria().eq(Car_.id,1)).intValue(),0); 136 | } 137 | 138 | @Test 139 | @UsingDataSet("cars.yml") 140 | public void shouldListCarsModel() { 141 | List cars = carService.listByModel("%porche%"); 142 | assertThat(cars).isNotNull().hasSize(2); 143 | } 144 | 145 | @Test 146 | @UsingDataSet("cars.yml") 147 | public void shouldPaginateCars() { 148 | Filter carFilter = new Filter().setFirst(0).setPageSize(1); 149 | List cars = carService.paginate(carFilter); 150 | assertNotNull(cars); 151 | assertEquals(cars.size(), 1); 152 | assertEquals(cars.get(0).getId(), new Integer(1)); 153 | carFilter.setFirst(1);//get second database page 154 | cars = carService.paginate(carFilter); 155 | assertNotNull(cars); 156 | assertEquals(cars.size(), 1); 157 | assertEquals(cars.get(0).getId(), new Integer(2)); 158 | carFilter.setFirst(0); 159 | carFilter.setPageSize(4); 160 | cars = carService.paginate(carFilter); 161 | assertEquals(cars.size(), 4); 162 | } 163 | 164 | @Test 165 | @UsingDataSet("cars.yml") 166 | public void shouldPaginateAndSortCars() { 167 | Filter carFilter = new Filter() 168 | .setFirst(0) 169 | .setPageSize(4) 170 | .setSortField("model") 171 | .setAdminSort(AdminSort.DESCENDING); 172 | List cars = carService.paginate(carFilter); 173 | assertThat(cars).isNotNull().hasSize(4); 174 | assertTrue(cars.get(0).getModel().equals("Porche274")); 175 | assertTrue(cars.get(3).getModel().equals("Ferrari")); 176 | } 177 | 178 | @Test 179 | @UsingDataSet("cars.yml") 180 | public void shouldPaginateCarsByModel() { 181 | Car carExample = new Car().model("Ferrari"); 182 | Filter carFilter = new Filter(). 183 | setFirst(0).setPageSize(4) 184 | .setEntity(carExample); 185 | List cars = carService.paginate(carFilter); 186 | assertThat(cars).isNotNull().hasSize(1) 187 | .extracting("model").contains("Ferrari"); 188 | } 189 | 190 | @Test 191 | @UsingDataSet("cars.yml") 192 | public void shouldPaginateCarsByPrice() { 193 | Car carExample = new Car().price(12999.0); 194 | Filter carFilter = new Filter().setFirst(0).setPageSize(2).setEntity(carExample); 195 | List cars = carService.paginate(carFilter); 196 | assertThat(cars).isNotNull().hasSize(1) 197 | .extracting("model").contains("Mustang"); 198 | } 199 | 200 | @Test 201 | @UsingDataSet("cars.yml") 202 | public void shouldPaginateCarsByIdInParam() { 203 | Filter carFilter = new Filter().setFirst(0).setPageSize(2).addParam("id", 1); 204 | List cars = carService.paginate(carFilter); 205 | assertThat(cars).isNotNull().hasSize(1) 206 | .extracting("id").contains(1); 207 | } 208 | 209 | @Test 210 | @UsingDataSet("cars.yml") 211 | @Transactional(value = TransactionMode.DISABLED) 212 | public void shouldListCarsByPrice() { 213 | List cars = carService.criteria() 214 | .between(Car_.price, 1000D, 2450.9) 215 | .orderAsc(Car_.price).getResultList(); 216 | //ferrari and porche 217 | assertThat(cars).isNotNull() 218 | .hasSize(2).extracting("model") 219 | .contains("Porche","Ferrari"); 220 | } 221 | 222 | @Test 223 | @UsingDataSet("cars.yml") 224 | public void shouldGetCarModels() { 225 | List models = carService.getModels("po"); 226 | //porche and Porche274 227 | assertThat(models).isNotNull().hasSize(2) 228 | .contains("Porche","Porche274"); 229 | } 230 | 231 | @Test 232 | @UsingDataSet("cars.yml") 233 | public void shoulListCarsUsingCrudUtility() { 234 | assertEquals(4, crudService.count().intValue()); 235 | long count = crudService.count(crudService.criteria() 236 | .likeIgnoreCase(Car_.model, "%porche%") 237 | .gtOrEq(Car_.price, 10000D)); 238 | assertEquals(1, count); 239 | 240 | } 241 | 242 | @Test 243 | @UsingDataSet("cars.yml") 244 | public void shouldFindCarsByExample() { 245 | Car carExample = new Car().model("Ferrari"); 246 | List cars = crudService.example(carExample,Car_.model).getResultList(); 247 | assertThat(cars).isNotNull().hasSize(1) 248 | .extracting("model") 249 | .contains("Ferrari"); 250 | 251 | carExample = new Car().model("porche").name("%avenger"); 252 | cars = crudService.exampleLike(carExample, Car_.name, Car_.model).getResultList(); 253 | 254 | assertThat(cars).isNotNull().hasSize(1) 255 | .extracting("name") 256 | .contains("porche avenger"); 257 | 258 | } 259 | 260 | @Test 261 | @UsingDataSet("cars.yml") 262 | public void shoulGetTotalPriceByModel() { 263 | assertEquals((Double) 20380.53, carService.getTotalPriceByModel(new Car().model("%porche%"))); 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /src/test/java/com/github/adminfaces/util/Deployments.java: -------------------------------------------------------------------------------- 1 | package com.github.adminfaces.util; 2 | 3 | import com.github.adminfaces.template.exception.BusinessException; 4 | import com.github.adminfaces.template.util.Assert; 5 | import org.jboss.shrinkwrap.api.ShrinkWrap; 6 | import org.jboss.shrinkwrap.api.spec.WebArchive; 7 | import org.jboss.shrinkwrap.resolver.api.maven.Maven; 8 | import org.jboss.shrinkwrap.resolver.api.maven.MavenResolverSystem; 9 | 10 | import java.io.File; 11 | 12 | /** 13 | * @author rafael-pestano 14 | * Arquillian WebArchive factory 15 | */ 16 | public class Deployments { 17 | 18 | 19 | protected static final String WEB_INF= "src/main/webapp/WEB-INF"; 20 | 21 | /** 22 | * @return base WebArchive for all arquillian tests 23 | */ 24 | public static WebArchive createDeployment() { 25 | WebArchive war = ShrinkWrap.create(WebArchive.class, "admin-starter-test.war"); 26 | war.addPackages(true, "com.github.adminfaces.starter"); 27 | war.addClasses(BusinessException.class, Assert.class); 28 | //LIBS 29 | MavenResolverSystem resolver = Maven.resolver(); 30 | war.addAsLibraries(resolver.loadPomFromFile("pom.xml").resolve("com.github.adminfaces:admin-persistence").withTransitivity().asFile()); 31 | war.addAsLibraries(resolver.loadPomFromFile("pom.xml").resolve("org.primefaces.extensions:primefaces-extensions").withTransitivity().asFile()); 32 | war.addAsLibraries(resolver.loadPomFromFile("pom.xml").resolve("org.omnifaces:omnifaces").withTransitivity().asFile()); 33 | 34 | 35 | //WEB-INF 36 | 37 | war.addAsWebInfResource(new File(WEB_INF,"beans.xml"), "beans.xml"); 38 | war.addAsWebInfResource(new File(WEB_INF,"web.xml"), "web.xml"); 39 | war.addAsWebInfResource(new File(WEB_INF,"faces-config.xml"), "faces-config.xml"); 40 | //resources 41 | war.addAsResource(new File("src/main/resources/META-INF/persistence.xml"), "META-INF/persistence.xml"); 42 | 43 | war.addAsResource(new File("src/main/resources/admin-config.properties"), "admin-config.properties"); 44 | war.addAsResource(new File("src/main/resources/messages.properties"), "messages.properties"); 45 | 46 | return war; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/test/resources/arquillian.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | ${arquillian.container} 12 | true 13 | -Xmx512m -Djboss.bind.address=localhost 14 | 15 | 16 | 17 | 18 | ${arquillian.browser} 19 | 1280x1024 20 | 74.0.3729.6 21 | 22 | 23 | 24 | 2 25 | 3 26 | 4 27 | 28 | 29 | 30 | java:jboss/datasources/ExampleDS 31 | CLEAN_INSERT 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/test/resources/chameleon/default/containers.yaml: -------------------------------------------------------------------------------- 1 | - name: JBoss EAP 2 | versionExpression: 7.* 3 | adapters: 4 | - type: remote 5 | coordinates: org.wildfly.arquillian:wildfly-arquillian-container-remote:2.0.1.Final 6 | adapterClass: org.jboss.as.arquillian.container.remote.RemoteDeployableContainer 7 | - type: managed 8 | coordinates: org.wildfly.arquillian:wildfly-arquillian-container-managed:2.0.1.Final 9 | adapterClass: org.jboss.as.arquillian.container.managed.ManagedDeployableContainer 10 | configuration: &EAP7_CONFIG 11 | jbossHome: ${dist} 12 | - type: embedded 13 | coordinates: org.wildfly.arquillian:wildfly-arquillian-container-embedded:2.0.1.Final 14 | adapterClass: org.jboss.as.arquillian.container.embedded.EmbeddedDeployableContainer 15 | configuration: *EAP7_CONFIG 16 | defaultType: managed 17 | dist: &EAP7_DIST 18 | coordinates: org.jboss.as:jboss-as-dist:zip:${version} 19 | exclude: &EAP7_EXCLUDE 20 | - org.jboss.arquillian.test:* 21 | - org.jboss.arquillian.testenricher:* 22 | - org.jboss.arquillian.container:* 23 | - org.jboss.arquillian.core:* 24 | - org.jboss.arquillian.config:* 25 | - org.jboss.arquillian.protocol:* 26 | - org.jboss.shrinkwrap.api:* 27 | - org.jboss.shrinkwrap:* 28 | - org.jboss.shrinkwrap.descriptors:* 29 | - org.jboss.shrinkwrap.resolver:* 30 | - name: JBoss EAP Domain 31 | versionExpression: 7.* 32 | adapters: 33 | - type: managed 34 | coordinates: org.wildfly.arquillian:wildfly-arquillian-container-domain-managed:2.0.1.Final 35 | adapterClass: org.jboss.as.arquillian.container.domain.managed.ManagedDomainDeployableContainer 36 | configuration: *EAP7_CONFIG 37 | - type: remote 38 | coordinates: org.wildfly.arquillian:wildfly-arquillian-container-domain-remote:2.0.1.Final 39 | adapterClass: org.jboss.as.arquillian.container.domain.remote.RemoteDomainDeployableContainer 40 | defaultType: managed 41 | dist: &EAP7_DIST 42 | coordinates: org.jboss.as:jboss-as-dist:zip:${version} 43 | exclude: &EAP7_EXCLUDE 44 | - org.jboss.arquillian.test:* 45 | - org.jboss.arquillian.testenricher:* 46 | - org.jboss.arquillian.container:* 47 | - org.jboss.arquillian.core:* 48 | - org.jboss.arquillian.config:* 49 | - org.jboss.arquillian.protocol:* 50 | - org.jboss.shrinkwrap.api:* 51 | - org.jboss.shrinkwrap:* 52 | - org.jboss.shrinkwrap.descriptors:* 53 | - org.jboss.shrinkwrap.resolver:* 54 | - name: JBoss EAP 55 | versionExpression: 6.0.* 56 | adapters: 57 | - type: remote 58 | coordinates: org.jboss.as:jboss-as-arquillian-container-remote:7.1.2.Final 59 | adapterClass: org.jboss.as.arquillian.container.remote.RemoteDeployableContainer 60 | - type: managed 61 | coordinates: org.jboss.as:jboss-as-arquillian-container-managed:7.1.2.Final 62 | adapterClass: org.jboss.as.arquillian.container.managed.ManagedDeployableContainer 63 | configuration: &EAP_CONFIG 64 | jbossHome: ${dist} 65 | - type: embedded 66 | coordinates: org.jboss.as:jboss-as-arquillian-container-embedded:7.1.2.Final 67 | adapterClass: org.jboss.as.arquillian.container.embedded.EmbeddedDeployableContainer 68 | configuration: *EAP_CONFIG 69 | defaultType: managed 70 | dist: &EAP_DIST 71 | coordinates: org.jboss.as:jboss-as-dist:zip:${version} 72 | defaultProtocol: Servlet 3.0 73 | exclude: &EAP_EXCLUDE 74 | - org.jboss.arquillian.test:* 75 | - org.jboss.arquillian.testenricher:* 76 | - org.jboss.arquillian.container:* 77 | - org.jboss.arquillian.core:* 78 | - org.jboss.arquillian.config:* 79 | - org.jboss.arquillian.protocol:* 80 | - org.jboss.shrinkwrap.api:* 81 | - org.jboss.shrinkwrap:* 82 | - org.jboss.shrinkwrap.descriptors:* 83 | - org.jboss.shrinkwrap.resolver:* 84 | - "*:wildfly-arquillian-testenricher-msc" 85 | - "*:wildfly-arquillian-protocol-jmx" 86 | - "*:jboss-as-arquillian-testenricher-msc" 87 | - "*:jboss-as-arquillian-protocol-jmx" 88 | - name: JBoss EAP Domain 89 | versionExpression: 6.0.* 90 | adapters: 91 | - type: managed 92 | coordinates: org.jboss.as:jboss-as-arquillian-container-domain-managed:7.1.2.Final 93 | adapterClass: org.jboss.as.arquillian.container.domain.managed.ManagedDomainDeployableContainer 94 | configuration: *EAP_CONFIG 95 | - type: remote 96 | coordinates: org.jboss.as:jboss-as-arquillian-container-domain-remote:7.1.2.Final 97 | adapterClass: org.jboss.as.arquillian.container.domain.remote.RemoteDomainDeployableContainer 98 | defaultType: managed 99 | dist: &EAP_DIST 100 | coordinates: org.jboss.as:jboss-as-dist:zip:${version} 101 | defaultProtocol: Servlet 3.0 102 | exclude: &EAP_EXCLUDE 103 | - org.jboss.arquillian.test:* 104 | - org.jboss.arquillian.testenricher:* 105 | - org.jboss.arquillian.container:* 106 | - org.jboss.arquillian.core:* 107 | - org.jboss.arquillian.config:* 108 | - org.jboss.arquillian.protocol:* 109 | - org.jboss.shrinkwrap.api:* 110 | - org.jboss.shrinkwrap:* 111 | - org.jboss.shrinkwrap.descriptors:* 112 | - org.jboss.shrinkwrap.resolver:* 113 | - "*:wildfly-arquillian-testenricher-msc" 114 | - "*:wildfly-arquillian-protocol-jmx" 115 | - "*:jboss-as-arquillian-testenricher-msc" 116 | - "*:jboss-as-arquillian-protocol-jmx" 117 | - name: JBoss EAP 118 | versionExpression: 6.* 119 | adapters: 120 | - type: remote 121 | coordinates: org.jboss.as:jboss-as-arquillian-container-remote:7.1.3.Final 122 | adapterClass: org.jboss.as.arquillian.container.remote.RemoteDeployableContainer 123 | - type: managed 124 | coordinates: org.jboss.as:jboss-as-arquillian-container-managed:7.1.3.Final 125 | adapterClass: org.jboss.as.arquillian.container.managed.ManagedDeployableContainer 126 | configuration: *EAP_CONFIG 127 | - type: embedded 128 | coordinates: org.jboss.as:jboss-as-arquillian-container-embedded:7.1.3.Final 129 | adapterClass: org.jboss.as.arquillian.container.embedded.EmbeddedDeployableContainer 130 | configuration: *EAP_CONFIG 131 | defaultType: managed 132 | dist: *EAP_DIST 133 | defaultProtocol: Servlet 3.0 134 | exclude: *EAP_EXCLUDE 135 | - name: JBoss EAP Domain 136 | versionExpression: 6.* 137 | adapters: 138 | - type: managed 139 | coordinates: org.jboss.as:jboss-as-arquillian-container-domain-managed:7.1.3.Final 140 | adapterClass: org.jboss.as.arquillian.container.domain.managed.ManagedDomainDeployableContainer 141 | configuration: *EAP_CONFIG 142 | - type: remote 143 | coordinates: org.jboss.as:jboss-as-arquillian-container-domain-remote:7.1.3.Final 144 | adapterClass: org.jboss.as.arquillian.container.domain.remote.RemoteDomainDeployableContainer 145 | defaultType: managed 146 | dist: *EAP_DIST 147 | defaultProtocol: Servlet 3.0 148 | exclude: *EAP_EXCLUDE 149 | - name: JBoss AS 150 | versionExpression: 7\.0\.[0-2]\.(.*)$|7\.1\.[0-1]\.(.*)$ 151 | adapters: 152 | - type: remote 153 | coordinates: org.jboss.as:jboss-as-arquillian-container-remote:${version} 154 | adapterClass: org.jboss.as.arquillian.container.remote.RemoteDeployableContainer 155 | - type: managed 156 | coordinates: org.jboss.as:jboss-as-arquillian-container-managed:${version} 157 | adapterClass: org.jboss.as.arquillian.container.managed.ManagedDeployableContainer 158 | configuration: &AS_CONFIG 159 | jbossHome: ${dist} 160 | - type: embedded 161 | coordinates: org.jboss.as:jboss-as-arquillian-container-embedded:${version} 162 | adapterClass: org.jboss.as.arquillian.container.embedded.EmbeddedDeployableContainer 163 | configuration: *AS_CONFIG 164 | defaultType: managed 165 | dist: &AS_DIST 166 | coordinates: org.jboss.as:jboss-as-dist:zip:${version} 167 | defaultProtocol: Servlet 3.0 168 | exclude: &AS_EXCLUDE 169 | - org.jboss.arquillian.test:* 170 | - org.jboss.arquillian.testenricher:* 171 | - org.jboss.arquillian.container:* 172 | - org.jboss.arquillian.core:* 173 | - org.jboss.arquillian.config:* 174 | - org.jboss.arquillian.protocol:* 175 | - org.jboss.shrinkwrap.api:* 176 | - org.jboss.shrinkwrap:* 177 | - org.jboss.shrinkwrap.descriptors:* 178 | - org.jboss.shrinkwrap.resolver:* 179 | - "*:wildfly-arquillian-testenricher-msc" 180 | - "*:wildfly-arquillian-protocol-jmx" 181 | - "*:jboss-as-arquillian-testenricher-msc" 182 | - "*:jboss-as-arquillian-protocol-jmx" 183 | - name: JBoss AS Domain 184 | versionExpression: 7\.0\.[0-2]\.(.*)$|7\.1\.[0-1]\.(.*)$ 185 | adapters: 186 | - type: managed 187 | coordinates: org.jboss.as:jboss-as-arquillian-container-domain-managed:${version} 188 | adapterClass: org.jboss.as.arquillian.container.domain.managed.ManagedDomainDeployableContainer 189 | configuration: *AS_CONFIG 190 | - type: remote 191 | coordinates: org.jboss.as:jboss-as-arquillian-container-domain-remote:${version} 192 | adapterClass: org.jboss.as.arquillian.container.domain.remote.RemoteDomainDeployableContainer 193 | defaultType: managed 194 | dist: &AS_DIST 195 | coordinates: org.jboss.as:jboss-as-dist:zip:${version} 196 | defaultProtocol: Servlet 3.0 197 | exclude: &AS_EXCLUDE 198 | - org.jboss.arquillian.test:* 199 | - org.jboss.arquillian.testenricher:* 200 | - org.jboss.arquillian.container:* 201 | - org.jboss.arquillian.core:* 202 | - org.jboss.arquillian.config:* 203 | - org.jboss.arquillian.protocol:* 204 | - org.jboss.shrinkwrap.api:* 205 | - org.jboss.shrinkwrap:* 206 | - org.jboss.shrinkwrap.descriptors:* 207 | - org.jboss.shrinkwrap.resolver:* 208 | - "*:wildfly-arquillian-testenricher-msc" 209 | - "*:wildfly-arquillian-protocol-jmx" 210 | - "*:jboss-as-arquillian-testenricher-msc" 211 | - "*:jboss-as-arquillian-protocol-jmx" 212 | - name: WildFly 213 | versionExpression: 8.* 214 | adapters: 215 | - type: remote 216 | coordinates: org.wildfly:wildfly-arquillian-container-remote:15.0.1.Final 217 | adapterClass: org.jboss.as.arquillian.container.remote.RemoteDeployableContainer 218 | - type: managed 219 | coordinates: org.wildfly:wildfly-arquillian-container-managed:15.0.1.Final 220 | adapterClass: org.jboss.as.arquillian.container.managed.ManagedDeployableContainer 221 | configuration: &WF_CONFIG 222 | jbossHome: ${dist} 223 | - type: embedded 224 | coordinates: org.wildfly:wildfly-arquillian-container-embedded:15.0.1.Final 225 | adapterClass: org.jboss.as.arquillian.container.embedded.EmbeddedDeployableContainer 226 | configuration: &WF_EMBEDD_CONFIG 227 | jbossHome: ${dist} 228 | modulePath: ${dist}/modules 229 | dependencies: 230 | - org.jboss.remotingjmx:remoting-jmx:2.0.1.Final 231 | - org.jboss.logging:jboss-logging:3.2.1.Final 232 | defaultType: managed 233 | dist: &WF_DIST 234 | coordinates: org.wildfly:wildfly-dist:zip:15.0.1 235 | defaultProtocol: Servlet 3.0 236 | exclude: &WF_EXCLUDE 237 | - org.jboss.arquillian.test:* 238 | - org.jboss.arquillian.testenricher:* 239 | - org.jboss.arquillian.container:* 240 | - org.jboss.arquillian.core:* 241 | - org.jboss.arquillian.config:* 242 | - org.jboss.arquillian.protocol:* 243 | - org.jboss.shrinkwrap.api:* 244 | - org.jboss.shrinkwrap:* 245 | - org.jboss.shrinkwrap.descriptors:* 246 | - org.jboss.shrinkwrap.resolver:* 247 | - "*:wildfly-arquillian-testenricher-msc" 248 | - "*:wildfly-arquillian-protocol-jmx" 249 | - "*:jboss-as-arquillian-testenricher-msc" 250 | - "*:jboss-as-arquillian-protocol-jmx" 251 | - name: WildFly Domain 252 | versionExpression: 8.* 253 | adapters: 254 | - type: managed 255 | coordinates: org.wildfly.arquillian:wildfly-arquillian-container-domain-managed:15.0.1.Final 256 | adapterClass: org.jboss.as.arquillian.container.domain.managed.ManagedDomainDeployableContainer 257 | configuration: *WF_CONFIG 258 | - type: remote 259 | coordinates: org.wildfly.arquillian:wildfly-arquillian-container-domain-remote:15.0.1.Final 260 | adapterClass: org.jboss.as.arquillian.container.domain.remote.RemoteDomainDeployableContainer 261 | defaultType: managed 262 | dist: &WF_DIST 263 | coordinates: org.wildfly:wildfly-dist:zip:15.0.1.Final 264 | defaultProtocol: Servlet 3.0 265 | exclude: &WF_EXCLUDE 266 | - org.jboss.arquillian.test:* 267 | - org.jboss.arquillian.testenricher:* 268 | - org.jboss.arquillian.container:* 269 | - org.jboss.arquillian.core:* 270 | - org.jboss.arquillian.config:* 271 | - org.jboss.arquillian.protocol:* 272 | - org.jboss.shrinkwrap.api:* 273 | - org.jboss.shrinkwrap:* 274 | - org.jboss.shrinkwrap.descriptors:* 275 | - org.jboss.shrinkwrap.resolver:* 276 | - "*:wildfly-arquillian-testenricher-msc" 277 | - "*:wildfly-arquillian-protocol-jmx" 278 | - "*:jboss-as-arquillian-testenricher-msc" 279 | - "*:jboss-as-arquillian-protocol-jmx" 280 | - name: WildFly 281 | versionExpression: 9.* 282 | adapters: 283 | - type: remote 284 | coordinates: org.wildfly.arquillian:wildfly-arquillian-container-remote:1.1.0.Final 285 | adapterClass: org.jboss.as.arquillian.container.remote.RemoteDeployableContainer 286 | - type: managed 287 | coordinates: org.wildfly.arquillian:wildfly-arquillian-container-managed:1.1.0.Final 288 | adapterClass: org.jboss.as.arquillian.container.managed.ManagedDeployableContainer 289 | configuration: *WF_CONFIG 290 | - type: embedded 291 | coordinates: org.wildfly.arquillian:wildfly-arquillian-container-embedded:1.1.0.Final 292 | adapterClass: org.jboss.as.arquillian.container.embedded.EmbeddedDeployableContainer 293 | configuration: *WF_EMBEDD_CONFIG 294 | dependencies: 295 | - org.jboss.remotingjmx:remoting-jmx:2.0.1.Final 296 | defaultType: managed 297 | dist: *WF_DIST 298 | exclude: &WF9_EXCLUDE 299 | - org.jboss.arquillian.test:* 300 | - org.jboss.arquillian.testenricher:* 301 | - org.jboss.arquillian.container:* 302 | - org.jboss.arquillian.core:* 303 | - org.jboss.arquillian.config:* 304 | - org.jboss.arquillian.protocol:* 305 | - org.jboss.shrinkwrap.api:* 306 | - org.jboss.shrinkwrap:* 307 | - org.jboss.shrinkwrap.descriptors:* 308 | - org.jboss.shrinkwrap.resolver:* 309 | - "*:wildfly-arquillian-testenricher-msc" 310 | - name: WildFly Domain 311 | versionExpression: 9.* 312 | adapters: 313 | - type: managed 314 | coordinates: org.wildfly.arquillian:wildfly-arquillian-container-domain-managed:1.1.0.Final 315 | adapterClass: org.jboss.as.arquillian.container.domain.managed.ManagedDomainDeployableContainer 316 | configuration: *WF_CONFIG 317 | - type: remote 318 | coordinates: org.wildfly.arquillian:wildfly-arquillian-container-domain-remote:1.1.0.Final 319 | adapterClass: org.jboss.as.arquillian.container.domain.remote.RemoteDomainDeployableContainer 320 | defaultType: managed 321 | dist: *WF_DIST 322 | exclude: &WF9_EXCLUDE 323 | - org.jboss.arquillian.test:* 324 | - org.jboss.arquillian.testenricher:* 325 | - org.jboss.arquillian.container:* 326 | - org.jboss.arquillian.core:* 327 | - org.jboss.arquillian.config:* 328 | - org.jboss.arquillian.protocol:* 329 | - org.jboss.shrinkwrap.api:* 330 | - org.jboss.shrinkwrap:* 331 | - org.jboss.shrinkwrap.descriptors:* 332 | - org.jboss.shrinkwrap.resolver:* 333 | - "*:wildfly-arquillian-testenricher-msc" 334 | - name: WildFly 335 | versionExpression: [10.*|11.*|12.*|13.*|14.*|15.*] 336 | adapters: 337 | - type: remote 338 | coordinates: org.wildfly.arquillian:wildfly-arquillian-container-remote:2.1.1.Final 339 | adapterClass: org.jboss.as.arquillian.container.remote.RemoteDeployableContainer 340 | - type: managed 341 | coordinates: org.wildfly.arquillian:wildfly-arquillian-container-managed:2.1.1.Final 342 | adapterClass: org.jboss.as.arquillian.container.managed.ManagedDeployableContainer 343 | configuration: *WF_CONFIG 344 | - type: embedded 345 | coordinates: org.wildfly.arquillian:wildfly-arquillian-container-embedded:2.1.1.Final 346 | adapterClass: org.jboss.as.arquillian.container.embedded.EmbeddedDeployableContainer 347 | configuration: *WF_EMBEDD_CONFIG 348 | defaultType: managed 349 | dist: *WF_DIST 350 | exclude: &WF10_EXCLUDE 351 | - org.jboss.arquillian.test:* 352 | - org.jboss.arquillian.testenricher:* 353 | - org.jboss.arquillian.container:* 354 | - org.jboss.arquillian.core:* 355 | - org.jboss.arquillian.config:* 356 | - org.jboss.arquillian.protocol:* 357 | - org.jboss.shrinkwrap.api:* 358 | - org.jboss.shrinkwrap:* 359 | - org.jboss.shrinkwrap.descriptors:* 360 | - org.jboss.shrinkwrap.resolver:* 361 | - "*:wildfly-arquillian-testenricher-msc" 362 | - name: WildFly Domain 363 | versionExpression: [10.*|11.*|12.*|13.*] 364 | adapters: 365 | - type: managed 366 | coordinates: org.wildfly.arquillian:wildfly-arquillian-container-domain-managed:2.1.1.Final 367 | adapterClass: org.jboss.as.arquillian.container.domain.managed.ManagedDomainDeployableContainer 368 | configuration: *WF_CONFIG 369 | - type: remote 370 | coordinates: org.wildfly.arquillian:wildfly-arquillian-container-domain-remote:2.1.1.Final 371 | adapterClass: org.jboss.as.arquillian.container.domain.remote.RemoteDomainDeployableContainer 372 | defaultType: managed 373 | dist: *WF_DIST 374 | exclude: &WF10_EXCLUDE 375 | - org.jboss.arquillian.test:* 376 | - org.jboss.arquillian.testenricher:* 377 | - org.jboss.arquillian.container:* 378 | - org.jboss.arquillian.core:* 379 | - org.jboss.arquillian.config:* 380 | - org.jboss.arquillian.protocol:* 381 | - org.jboss.shrinkwrap.api:* 382 | - org.jboss.shrinkwrap:* 383 | - org.jboss.shrinkwrap.descriptors:* 384 | - org.jboss.shrinkwrap.resolver:* 385 | - "*:wildfly-arquillian-testenricher-msc" 386 | 387 | # Older versions of Glassfish (before 3.1.2) are no longer supported 388 | - name: GlassFish 389 | versionExpression: ^3\.1\.[2-9]{1}(\.[0-9])*$ 390 | adapters: 391 | - &GF_REMOTE 392 | type: remote 393 | coordinates: org.jboss.arquillian.container:arquillian-glassfish-remote-3.1:1.0.2 394 | adapterClass: org.jboss.arquillian.container.glassfish.remote_3_1.GlassFishRestDeployableContainer 395 | - &GF_MANAGED 396 | type: managed 397 | coordinates: org.jboss.arquillian.container:arquillian-glassfish-managed-3.1:1.0.2 398 | adapterClass: org.jboss.arquillian.container.glassfish.managed_3_1.GlassFishManagedDeployableContainer 399 | configuration: 400 | glassFishHome: ${dist} 401 | outputToConsole: true 402 | - &GF_EMBEDDED 403 | type: embedded 404 | coordinates: org.jboss.arquillian.container:arquillian-glassfish-embedded-3.1:1.0.2 405 | adapterClass: org.jboss.arquillian.container.glassfish.embedded_3_1.GlassFishContainer 406 | requireDist: false 407 | dependencies: 408 | - org.glassfish.main.extras:glassfish-embedded-all:${version} 409 | defaultType: managed 410 | dist: &GF_DIST 411 | coordinates: org.glassfish.main.distributions:glassfish:zip:${version} 412 | 413 | - name: GlassFish 414 | versionExpression: 4.1.* 415 | adapters: 416 | - *GF_REMOTE 417 | - *GF_MANAGED 418 | - *GF_EMBEDDED 419 | defaultType: managed 420 | dist: *GF_DIST 421 | 422 | - name: GlassFish 423 | versionExpression: 5.* 424 | adapters: 425 | - *GF_REMOTE 426 | - *GF_MANAGED 427 | - *GF_EMBEDDED 428 | defaultType: managed 429 | dist: *GF_DIST 430 | 431 | - name: Payara 432 | versionExpression: [4.*|5.*] 433 | adapters: 434 | - *GF_REMOTE 435 | - *GF_MANAGED 436 | - type: embedded 437 | coordinates: org.jboss.arquillian.container:arquillian-glassfish-embedded-3.1:1.0.2 438 | adapterClass: org.jboss.arquillian.container.glassfish.embedded_3_1.GlassFishContainer 439 | requireDist: false 440 | dependencies: 441 | - fish.payara.extras:payara-embedded-all:${version} 442 | defaultType: managed 443 | dist: 444 | coordinates: fish.payara.distributions:payara:zip:${version} 445 | 446 | - name: Tomcat 447 | versionExpression: 6.* 448 | adapters: 449 | - type: remote 450 | coordinates: org.jboss.arquillian.container:arquillian-tomcat-remote-6:1.0.0.CR9 451 | adapterClass: org.jboss.arquillian.container.tomcat.remote.Tomcat6RemoteContainer 452 | - type: managed 453 | coordinates: org.jboss.arquillian.container:arquillian-tomcat-managed-6:1.0.0.CR9 454 | adapterClass: org.jboss.arquillian.container.tomcat.managed.Tomcat6ManagedContainer 455 | configuration: &TOMCAT_MANAGED_CONFIG 456 | catalinaHome: ${dist} 457 | catalinaBase: ${dist} 458 | defaultType: managed 459 | dist: 460 | coordinates: http://archive.apache.org/dist/tomcat/tomcat-6/v${version}/bin/apache-tomcat-${version}.zip 461 | 462 | - name: Tomcat 463 | versionExpression: 7.* 464 | adapters: 465 | - type: remote 466 | coordinates: org.jboss.arquillian.container:arquillian-tomcat-remote-7:1.0.0.CR9 467 | adapterClass: org.jboss.arquillian.container.tomcat.remote.Tomcat7RemoteContainer 468 | - type: managed 469 | coordinates: org.jboss.arquillian.container:arquillian-tomcat-managed-7:1.0.0.CR9 470 | adapterClass: org.jboss.arquillian.container.tomcat.managed.Tomcat7ManagedContainer 471 | configuration: *TOMCAT_MANAGED_CONFIG 472 | defaultType: managed 473 | dist: &TOMCAT_DIST 474 | coordinates: org.apache.tomcat:tomcat:zip:${version} 475 | 476 | - name: Tomcat 477 | versionExpression: 8.0.* 478 | adapters: 479 | - type: remote 480 | coordinates: org.jboss.arquillian.container:arquillian-tomcat-remote-8:1.0.0.CR9 481 | adapterClass: org.jboss.arquillian.container.tomcat.remote.Tomcat8RemoteContainer 482 | - type: managed 483 | coordinates: org.jboss.arquillian.container:arquillian-tomcat-managed-8:1.0.0.CR9 484 | adapterClass: org.jboss.arquillian.container.tomcat.managed.Tomcat8ManagedContainer 485 | configuration: *TOMCAT_MANAGED_CONFIG 486 | defaultType: managed 487 | dist: *TOMCAT_DIST 488 | 489 | - name: TomEE 490 | versionExpression: 1.* 491 | adapters: 492 | - type: remote 493 | coordinates: org.apache.openejb:arquillian-tomee-remote:${version} 494 | adapterClass: org.apache.tomee.arquillian.remote.RemoteTomEEContainer 495 | - type: managed 496 | coordinates: org.apache.openejb:arquillian-tomee-remote:${version} 497 | adapterClass: org.apache.tomee.arquillian.remote.RemoteTomEEContainer 498 | requireDist: false 499 | - type: embedded 500 | coordinates: org.apache.openejb:arquillian-tomee-embedded:${version} 501 | adapterClass: org.apache.openejb.arquillian.embedded.EmbeddedTomEEContainer 502 | requireDist: false 503 | dist: 504 | coordinates: org.apache.openejb:apache-tomee:zip:${version} 505 | 506 | - name: TomEE 507 | versionExpression: [7.*|8.*] 508 | adapters: 509 | - type: remote 510 | coordinates: org.apache.tomee:arquillian-tomee-remote:${version} 511 | adapterClass: org.apache.tomee.arquillian.remote.RemoteTomEEContainer 512 | - type: managed 513 | coordinates: org.apache.tomee:arquillian-tomee-remote:${version} 514 | adapterClass: org.apache.tomee.arquillian.remote.RemoteTomEEContainer 515 | requireDist: false 516 | - type: embedded 517 | coordinates: org.apache.tomee:arquillian-tomee-embedded:${version} 518 | adapterClass: org.apache.openejb.arquillian.embedded.EmbeddedTomEEContainer 519 | requireDist: false 520 | dist: 521 | coordinates: org.apache.tomee:apache-tomee:zip:${version} 522 | -------------------------------------------------------------------------------- /src/test/resources/datasets/cars.yml: -------------------------------------------------------------------------------- 1 | car: 2 | - id: 1 3 | model: "Ferrari" 4 | name: "ferrari spider" 5 | price: 2450.8 6 | version: 0 7 | - id: 2 8 | model: "Mustang" 9 | name: "mustang spider" 10 | price: 12999.0 11 | version: 0 12 | - id: 3 13 | model: "Porche" 14 | name: "porche avenger" 15 | price: 1390.3 16 | version: 0 17 | - id: 4 18 | model: "Porche274" 19 | name: "porche rally" 20 | price: 18990.23 21 | version: 0 -------------------------------------------------------------------------------- /starter1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter-persistence/98b86adbf83bb32433381a613c2d03f8d5612c9a/starter1.png -------------------------------------------------------------------------------- /starter2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter-persistence/98b86adbf83bb32433381a613c2d03f8d5612c9a/starter2.png -------------------------------------------------------------------------------- /starter3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter-persistence/98b86adbf83bb32433381a613c2d03f8d5612c9a/starter3.png -------------------------------------------------------------------------------- /starter4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter-persistence/98b86adbf83bb32433381a613c2d03f8d5612c9a/starter4.png -------------------------------------------------------------------------------- /starter5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adminfaces/admin-starter-persistence/98b86adbf83bb32433381a613c2d03f8d5612c9a/starter5.png --------------------------------------------------------------------------------