mirror of
https://github.com/spring-projects/spring-petclinic.git
synced 2025-07-17 13:05:49 +00:00
Merge branch 'main' into feature/my-change
Signed-off-by: prankumargrid <prankumar@griddynamics.com>
This commit is contained in:
commit
0f242dd9bc
73 changed files with 1078 additions and 555 deletions
|
@ -17,6 +17,8 @@ cd spring-petclinic
|
||||||
java -jar target/*.jar
|
java -jar target/*.jar
|
||||||
```
|
```
|
||||||
|
|
||||||
|
(On Windows, or if your shell doesn't expand the glob, you might need to specify the JAR file name explicitly on the command line at the end there.)
|
||||||
|
|
||||||
You can then access the Petclinic at <http://localhost:8080/>.
|
You can then access the Petclinic at <http://localhost:8080/>.
|
||||||
|
|
||||||
<img width="1042" alt="petclinic-screenshot" src="https://cloud.githubusercontent.com/assets/838318/19727082/2aee6d6c-9b8e-11e6-81fe-e889a5ddfded.png">
|
<img width="1042" alt="petclinic-screenshot" src="https://cloud.githubusercontent.com/assets/838318/19727082/2aee6d6c-9b8e-11e6-81fe-e889a5ddfded.png">
|
||||||
|
@ -52,13 +54,13 @@ A similar setup is provided for MySQL and PostgreSQL if a persistent database co
|
||||||
You can start MySQL or PostgreSQL locally with whatever installer works for your OS or use docker:
|
You can start MySQL or PostgreSQL locally with whatever installer works for your OS or use docker:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -e MYSQL_USER=petclinic -e MYSQL_PASSWORD=petclinic -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=petclinic -p 3306:3306 mysql:9.1
|
docker run -e MYSQL_USER=petclinic -e MYSQL_PASSWORD=petclinic -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=petclinic -p 3306:3306 mysql:9.2
|
||||||
```
|
```
|
||||||
|
|
||||||
or
|
or
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -e POSTGRES_USER=petclinic -e POSTGRES_PASSWORD=petclinic -e POSTGRES_DB=petclinic -p 5432:5432 postgres:17.0
|
docker run -e POSTGRES_USER=petclinic -e POSTGRES_PASSWORD=petclinic -e POSTGRES_DB=petclinic -p 5432:5432 postgres:17.5
|
||||||
```
|
```
|
||||||
|
|
||||||
Further documentation is provided for [MySQL](https://github.com/spring-projects/spring-petclinic/blob/main/src/main/resources/db/mysql/petclinic_db_setup_mysql.txt)
|
Further documentation is provided for [MySQL](https://github.com/spring-projects/spring-petclinic/blob/main/src/main/resources/db/mysql/petclinic_db_setup_mysql.txt)
|
||||||
|
|
13
build.gradle
13
build.gradle
|
@ -19,7 +19,7 @@ apply plugin: 'io.spring.javaformat'
|
||||||
gradle.startParameter.excludedTaskNames += [ "checkFormatAot", "checkFormatAotTest" ]
|
gradle.startParameter.excludedTaskNames += [ "checkFormatAot", "checkFormatAotTest" ]
|
||||||
|
|
||||||
group = 'org.springframework.samples'
|
group = 'org.springframework.samples'
|
||||||
version = '3.4.0'
|
version = '3.5.0'
|
||||||
|
|
||||||
java {
|
java {
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
@ -37,16 +37,13 @@ repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
ext.checkstyleVersion = "10.20.1"
|
ext.checkstyleVersion = "10.25.0"
|
||||||
ext.springJavaformatCheckstyleVersion = "0.0.43"
|
ext.springJavaformatCheckstyleVersion = "0.0.46"
|
||||||
ext.webjarsLocatorLiteVersion = "1.0.1"
|
ext.webjarsLocatorLiteVersion = "1.1.0"
|
||||||
ext.webjarsFontawesomeVersion = "4.7.0"
|
ext.webjarsFontawesomeVersion = "4.7.0"
|
||||||
ext.webjarsBootstrapVersion = "5.3.3"
|
ext.webjarsBootstrapVersion = "5.3.6"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// Workaround for AOT issue (https://github.com/spring-projects/spring-framework/pull/33949) -->
|
|
||||||
implementation 'io.projectreactor:reactor-core'
|
|
||||||
|
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-cache'
|
implementation 'org.springframework.boot:spring-boot-starter-cache'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
services:
|
services:
|
||||||
mysql:
|
mysql:
|
||||||
image: mysql:9.1
|
image: mysql:9.2
|
||||||
ports:
|
ports:
|
||||||
- "3306:3306"
|
- "3306:3306"
|
||||||
environment:
|
environment:
|
||||||
|
@ -12,7 +12,7 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- "./conf.d:/etc/mysql/conf.d:ro"
|
- "./conf.d:/etc/mysql/conf.d:ro"
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:17.0
|
image: postgres:17.5
|
||||||
ports:
|
ports:
|
||||||
- "5432:5432"
|
- "5432:5432"
|
||||||
environment:
|
environment:
|
||||||
|
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|
9
gradlew
vendored
9
gradlew
vendored
|
@ -86,8 +86,7 @@ done
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||||
' "$PWD" ) || exit
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
|
@ -115,7 +114,7 @@ case "$( uname )" in #(
|
||||||
NONSTOP* ) nonstop=true ;;
|
NONSTOP* ) nonstop=true ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
CLASSPATH="\\\"\\\""
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
|
@ -206,7 +205,7 @@ fi
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Collect all arguments for the java command:
|
# Collect all arguments for the java command:
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
# and any embedded shellness will be escaped.
|
# and any embedded shellness will be escaped.
|
||||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
# treated as '${Hostname}' itself on the command line.
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
@ -214,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
-classpath "$CLASSPATH" \
|
-classpath "$CLASSPATH" \
|
||||||
org.gradle.wrapper.GradleWrapperMain \
|
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||||
"$@"
|
"$@"
|
||||||
|
|
||||||
# Stop when "xargs" is not available.
|
# Stop when "xargs" is not available.
|
||||||
|
|
4
gradlew.bat
vendored
4
gradlew.bat
vendored
|
@ -70,11 +70,11 @@ goto fail
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
set CLASSPATH=
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
|
|
@ -41,7 +41,7 @@ spec:
|
||||||
app: demo-db
|
app: demo-db
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- image: postgres:17
|
- image: postgres:17.5
|
||||||
name: postgresql
|
name: postgresql
|
||||||
env:
|
env:
|
||||||
- name: POSTGRES_USER
|
- name: POSTGRES_USER
|
||||||
|
|
28
pom.xml
28
pom.xml
|
@ -5,13 +5,13 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
<version>3.4.2</version>
|
<version>3.5.0</version>
|
||||||
<relativePath></relativePath>
|
<relativePath></relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>org.springframework.samples</groupId>
|
<groupId>org.springframework.samples</groupId>
|
||||||
<artifactId>spring-petclinic</artifactId>
|
<artifactId>spring-petclinic</artifactId>
|
||||||
<version>3.4.0-SNAPSHOT</version>
|
<version>3.5.0-SNAPSHOT</version>
|
||||||
|
|
||||||
<name>petclinic</name>
|
<name>petclinic</name>
|
||||||
|
|
||||||
|
@ -21,22 +21,21 @@
|
||||||
<java.version>17</java.version>
|
<java.version>17</java.version>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
<!-- Important for reproducible builds. Update using e.g. ./mvnw versions:set
|
<!-- Important for reproducible builds. Update using e.g. ./mvnw versions:set -DnewVersion=... -->
|
||||||
-DnewVersion=... -->
|
|
||||||
<project.build.outputTimestamp>2024-11-28T14:37:52Z</project.build.outputTimestamp>
|
<project.build.outputTimestamp>2024-11-28T14:37:52Z</project.build.outputTimestamp>
|
||||||
|
|
||||||
<!-- Web dependencies -->
|
<!-- Web dependencies -->
|
||||||
<webjars-locator.version>1.0.1</webjars-locator.version>
|
<webjars-locator.version>1.1.0</webjars-locator.version>
|
||||||
<webjars-bootstrap.version>5.3.3</webjars-bootstrap.version>
|
<webjars-bootstrap.version>5.3.6</webjars-bootstrap.version>
|
||||||
<webjars-font-awesome.version>4.7.0</webjars-font-awesome.version>
|
<webjars-font-awesome.version>4.7.0</webjars-font-awesome.version>
|
||||||
|
|
||||||
<checkstyle.version>10.20.1</checkstyle.version>
|
<checkstyle.version>10.25.0</checkstyle.version>
|
||||||
<jacoco.version>0.8.12</jacoco.version>
|
<jacoco.version>0.8.13</jacoco.version>
|
||||||
<libsass.version>0.2.29</libsass.version>
|
<libsass.version>0.3.4</libsass.version>
|
||||||
<lifecycle-mapping>1.0.0</lifecycle-mapping>
|
<lifecycle-mapping>1.0.0</lifecycle-mapping>
|
||||||
<maven-checkstyle.version>3.6.0</maven-checkstyle.version>
|
<maven-checkstyle.version>3.6.0</maven-checkstyle.version>
|
||||||
<nohttp-checkstyle.version>0.0.11</nohttp-checkstyle.version>
|
<nohttp-checkstyle.version>0.0.11</nohttp-checkstyle.version>
|
||||||
<spring-format.version>0.0.43</spring-format.version>
|
<spring-format.version>0.0.46</spring-format.version>
|
||||||
|
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
@ -71,11 +70,6 @@
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<!-- Workaround for AOT issue (https://github.com/spring-projects/spring-framework/pull/33949) -->
|
|
||||||
<groupId>io.projectreactor</groupId>
|
|
||||||
<artifactId>reactor-core</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Databases - Uses H2 by default -->
|
<!-- Databases - Uses H2 by default -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -168,9 +162,7 @@
|
||||||
<configuration>
|
<configuration>
|
||||||
<rules>
|
<rules>
|
||||||
<requireJavaVersion>
|
<requireJavaVersion>
|
||||||
<message>This build requires at least Java ${java.version},
|
<message>This build requires at least Java ${java.version}, update your JVM, and run the build again</message>
|
||||||
update your JVM, and
|
|
||||||
run the build again</message>
|
|
||||||
<version>${java.version}</version>
|
<version>${java.version}</version>
|
||||||
</requireJavaVersion>
|
</requireJavaVersion>
|
||||||
</rules>
|
</rules>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -24,7 +24,6 @@ import org.springframework.context.annotation.ImportRuntimeHints;
|
||||||
* PetClinic Spring Boot Application.
|
* PetClinic Spring Boot Application.
|
||||||
*
|
*
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@ImportRuntimeHints(PetClinicRuntimeHints.class)
|
@ImportRuntimeHints(PetClinicRuntimeHints.class)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -57,7 +57,7 @@ public class Owner extends Person {
|
||||||
|
|
||||||
@Column(name = "telephone")
|
@Column(name = "telephone")
|
||||||
@NotBlank
|
@NotBlank
|
||||||
@Pattern(regexp = "\\d{10}", message = "Telephone must be a 10-digit number")
|
@Pattern(regexp = "\\d{10}", message = "{telephone.invalid}")
|
||||||
private String telephone;
|
private String telephone;
|
||||||
|
|
||||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -25,7 +25,7 @@ import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.data.jpa.repository.Query;
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Repository class for <code>Owner</code> domain objects All method names are compliant
|
* Repository class for <code>Owner</code> domain objects. All method names are compliant
|
||||||
* with Spring Data naming conventions so this interface can easily be extended for Spring
|
* with Spring Data naming conventions so this interface can easily be extended for Spring
|
||||||
* Data. See:
|
* Data. See:
|
||||||
* https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
|
* https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
|
||||||
|
@ -38,13 +38,6 @@ import org.springframework.data.jpa.repository.Query;
|
||||||
*/
|
*/
|
||||||
public interface OwnerRepository extends JpaRepository<Owner, Integer> {
|
public interface OwnerRepository extends JpaRepository<Owner, Integer> {
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve all {@link PetType}s from the data store.
|
|
||||||
* @return a Collection of {@link PetType}s.
|
|
||||||
*/
|
|
||||||
@Query("SELECT ptype FROM PetType ptype ORDER BY ptype.name")
|
|
||||||
List<PetType> findPetTypes();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve {@link Owner}s from the data store by last name, returning all owners
|
* Retrieve {@link Owner}s from the data store by last name, returning all owners
|
||||||
* whose last name <i>starts</i> with the given name.
|
* whose last name <i>starts</i> with the given name.
|
||||||
|
@ -69,9 +62,4 @@ public interface OwnerRepository extends JpaRepository<Owner, Integer> {
|
||||||
*/
|
*/
|
||||||
Optional<Owner> findById(@Nonnull Integer id);
|
Optional<Owner> findById(@Nonnull Integer id);
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns all the owners from data store
|
|
||||||
**/
|
|
||||||
Page<Owner> findAll(Pageable pageable);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -48,13 +48,16 @@ class PetController {
|
||||||
|
|
||||||
private final OwnerRepository owners;
|
private final OwnerRepository owners;
|
||||||
|
|
||||||
public PetController(OwnerRepository owners) {
|
private final PetTypeRepository types;
|
||||||
|
|
||||||
|
public PetController(OwnerRepository owners, PetTypeRepository types) {
|
||||||
this.owners = owners;
|
this.owners = owners;
|
||||||
|
this.types = types;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ModelAttribute("types")
|
@ModelAttribute("types")
|
||||||
public Collection<PetType> populatePetTypes() {
|
public Collection<PetType> populatePetTypes() {
|
||||||
return this.owners.findPetTypes();
|
return this.types.findPetTypes();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ModelAttribute("owner")
|
@ModelAttribute("owner")
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.samples.petclinic.owner;
|
package org.springframework.samples.petclinic.owner;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.format.Formatter;
|
import org.springframework.format.Formatter;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@ -36,11 +35,10 @@ import java.util.Locale;
|
||||||
@Component
|
@Component
|
||||||
public class PetTypeFormatter implements Formatter<PetType> {
|
public class PetTypeFormatter implements Formatter<PetType> {
|
||||||
|
|
||||||
private final OwnerRepository owners;
|
private final PetTypeRepository types;
|
||||||
|
|
||||||
@Autowired
|
public PetTypeFormatter(PetTypeRepository types) {
|
||||||
public PetTypeFormatter(OwnerRepository owners) {
|
this.types = types;
|
||||||
this.owners = owners;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -50,7 +48,7 @@ public class PetTypeFormatter implements Formatter<PetType> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PetType parse(String text, Locale locale) throws ParseException {
|
public PetType parse(String text, Locale locale) throws ParseException {
|
||||||
Collection<PetType> findPetTypes = this.owners.findPetTypes();
|
Collection<PetType> findPetTypes = this.types.findPetTypes();
|
||||||
for (PetType type : findPetTypes) {
|
for (PetType type : findPetTypes) {
|
||||||
if (type.getName().equals(text)) {
|
if (type.getName().equals(text)) {
|
||||||
return type;
|
return type;
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2025 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.samples.petclinic.owner;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import jakarta.annotation.Nonnull;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repository class for <code>PetType</code> domain objects.
|
||||||
|
*
|
||||||
|
* @author Patrick Baumgartner
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface PetTypeRepository extends JpaRepository<PetType, Integer> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve all {@link PetType}s from the data store.
|
||||||
|
* @return a Collection of {@link PetType}s.
|
||||||
|
*/
|
||||||
|
@Query("SELECT ptype FROM PetType ptype ORDER BY ptype.name")
|
||||||
|
List<PetType> findPetTypes();
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
package org.springframework.samples.petclinic.system;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.LocaleResolver;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
|
||||||
|
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures internationalization (i18n) support for the application.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Handles loading language-specific messages, tracking the user's language, and allowing
|
||||||
|
* language changes via the URL parameter (e.g., <code>?lang=de</code>).
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Anuj Ashok Potdar
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class WebConfiguration implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses session storage to remember the user’s language setting across requests.
|
||||||
|
* Defaults to English if nothing is specified.
|
||||||
|
* @return session-based {@link LocaleResolver}
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public LocaleResolver localeResolver() {
|
||||||
|
SessionLocaleResolver resolver = new SessionLocaleResolver();
|
||||||
|
resolver.setDefaultLocale(Locale.ENGLISH);
|
||||||
|
return resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the app to switch languages using a URL parameter like
|
||||||
|
* <code>?lang=es</code>.
|
||||||
|
* @return a {@link LocaleChangeInterceptor} that handles the change
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public LocaleChangeInterceptor localeChangeInterceptor() {
|
||||||
|
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
|
||||||
|
interceptor.setParamName("lang");
|
||||||
|
return interceptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the locale change interceptor so it can run on each request.
|
||||||
|
* @param registry where interceptors are added
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
|
registry.addInterceptor(localeChangeInterceptor());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# database init, supports postgres too
|
||||||
database=postgres
|
database=postgres
|
||||||
spring.datasource.url=${POSTGRES_URL:jdbc:postgresql://localhost/petclinic}
|
spring.datasource.url=${POSTGRES_URL:jdbc:postgresql://localhost/petclinic}
|
||||||
spring.datasource.username=${POSTGRES_USER:petclinic}
|
spring.datasource.username=${POSTGRES_USER:petclinic}
|
||||||
|
|
|
@ -6,3 +6,43 @@ nonNumeric=must be all numeric
|
||||||
duplicateFormSubmission=Duplicate form submission is not allowed
|
duplicateFormSubmission=Duplicate form submission is not allowed
|
||||||
typeMismatch.date=invalid date
|
typeMismatch.date=invalid date
|
||||||
typeMismatch.birthDate=invalid date
|
typeMismatch.birthDate=invalid date
|
||||||
|
owner=Owner
|
||||||
|
firstName=First Name
|
||||||
|
lastName=Last Name
|
||||||
|
address=Address
|
||||||
|
city=City
|
||||||
|
telephone=Telephone
|
||||||
|
owners=Owners
|
||||||
|
addOwner=Add Owner
|
||||||
|
findOwner=Find Owner
|
||||||
|
findOwners=Find Owners
|
||||||
|
updateOwner=Update Owner
|
||||||
|
vets=Veterinarians
|
||||||
|
name=Name
|
||||||
|
specialties=Specialties
|
||||||
|
none=none
|
||||||
|
pages=pages
|
||||||
|
first=First
|
||||||
|
next=Next
|
||||||
|
previous=Previous
|
||||||
|
last=Last
|
||||||
|
somethingHappened=Something happened...
|
||||||
|
pets=Pets
|
||||||
|
home=Home
|
||||||
|
error=Error
|
||||||
|
telephone.invalid=Telephone must be a 10-digit number
|
||||||
|
layoutTitle=PetClinic :: a Spring Framework demonstration
|
||||||
|
pet=Pet
|
||||||
|
birthDate=Birth Date
|
||||||
|
type=Type
|
||||||
|
previousVisits=Previous Visits
|
||||||
|
date=Date
|
||||||
|
description=Description
|
||||||
|
new=New
|
||||||
|
addVisit=Add Visit
|
||||||
|
editPet=Edit Pet
|
||||||
|
ownerInformation=Owner Information
|
||||||
|
visitDate=Visit Date
|
||||||
|
editOwner=Edit Owner
|
||||||
|
addNewPet=Add New Pet
|
||||||
|
petsAndVisits=Pets and Visits
|
||||||
|
|
|
@ -6,4 +6,43 @@ nonNumeric=darf nur numerisch sein
|
||||||
duplicateFormSubmission=Wiederholtes Absenden des Formulars ist nicht erlaubt
|
duplicateFormSubmission=Wiederholtes Absenden des Formulars ist nicht erlaubt
|
||||||
typeMismatch.date=ung<EFBFBD>ltiges Datum
|
typeMismatch.date=ung<EFBFBD>ltiges Datum
|
||||||
typeMismatch.birthDate=ung<EFBFBD>ltiges Datum
|
typeMismatch.birthDate=ung<EFBFBD>ltiges Datum
|
||||||
|
owner=Besitzer
|
||||||
|
firstName=Vorname
|
||||||
|
lastName=Nachname
|
||||||
|
address=Adresse
|
||||||
|
city=Stadt
|
||||||
|
telephone=Telefon
|
||||||
|
owners=Besitzer
|
||||||
|
addOwner=Besitzer hinzufügen
|
||||||
|
findOwner=Besitzer finden
|
||||||
|
findOwners=Besitzer suchen
|
||||||
|
updateOwner=Besitzer aktualisieren
|
||||||
|
vets=Tierärzte
|
||||||
|
name=Name
|
||||||
|
specialties=Fachgebiete
|
||||||
|
none=keine
|
||||||
|
pages=Seiten
|
||||||
|
first=Erste
|
||||||
|
next=Nächste
|
||||||
|
previous=Vorherige
|
||||||
|
last=Letzte
|
||||||
|
somethingHappened=Etwas ist passiert...
|
||||||
|
pets=Haustiere
|
||||||
|
home=Startseite
|
||||||
|
error=Fehler
|
||||||
|
telephone.invalid=Telefonnummer muss aus 10 Ziffern bestehen
|
||||||
|
layoutTitle=PetClinic :: eine Demonstration des Spring Frameworks
|
||||||
|
pet=Haustier
|
||||||
|
birthDate=Geburtsdatum
|
||||||
|
type=Typ
|
||||||
|
previousVisits=Frühere Besuche
|
||||||
|
date=Datum
|
||||||
|
description=Beschreibung
|
||||||
|
new=Neu
|
||||||
|
addVisit=Besuch hinzufügen
|
||||||
|
editPet=Haustier bearbeiten
|
||||||
|
ownerInformation=Besitzerinformationen
|
||||||
|
visitDate=Besuchsdatum
|
||||||
|
editOwner=Besitzer bearbeiten
|
||||||
|
addNewPet=Neues Haustier hinzufügen
|
||||||
|
petsAndVisits=Haustiere und Besuche
|
||||||
|
|
|
@ -6,4 +6,43 @@ nonNumeric=Sólo debe contener numeros
|
||||||
duplicateFormSubmission=No se permite el envío de formularios duplicados
|
duplicateFormSubmission=No se permite el envío de formularios duplicados
|
||||||
typeMismatch.date=Fecha invalida
|
typeMismatch.date=Fecha invalida
|
||||||
typeMismatch.birthDate=Fecha invalida
|
typeMismatch.birthDate=Fecha invalida
|
||||||
|
owner=Propietario
|
||||||
|
firstName=Nombre
|
||||||
|
lastName=Apellido
|
||||||
|
address=Dirección
|
||||||
|
city=Ciudad
|
||||||
|
telephone=Teléfono
|
||||||
|
owners=Propietarios
|
||||||
|
addOwner=Añadir propietario
|
||||||
|
findOwner=Buscar propietario
|
||||||
|
findOwners=Buscar propietarios
|
||||||
|
updateOwner=Actualizar propietario
|
||||||
|
vets=Veterinarios
|
||||||
|
name=Nombre
|
||||||
|
specialties=Especialidades
|
||||||
|
none=ninguno
|
||||||
|
pages=páginas
|
||||||
|
first=Primero
|
||||||
|
next=Siguiente
|
||||||
|
previous=Anterior
|
||||||
|
last=Último
|
||||||
|
somethingHappened=Algo pasó...
|
||||||
|
pets=Mascotas
|
||||||
|
home=Inicio
|
||||||
|
error=Error
|
||||||
|
telephone.invalid=El número de teléfono debe tener 10 dígitos
|
||||||
|
layoutTitle=PetClinic :: una demostración de Spring Framework
|
||||||
|
pet=Mascota
|
||||||
|
birthDate=Fecha de nacimiento
|
||||||
|
type=Tipo
|
||||||
|
previousVisits=Visitas anteriores
|
||||||
|
date=Fecha
|
||||||
|
description=Descripción
|
||||||
|
new=Nuevo
|
||||||
|
addVisit=Agregar visita
|
||||||
|
editPet=Editar mascota
|
||||||
|
ownerInformation=Información del propietario
|
||||||
|
visitDate=Fecha de visita
|
||||||
|
editOwner=Editar propietario
|
||||||
|
addNewPet=Agregar nueva mascota
|
||||||
|
petsAndVisits=Mascotas y visitas
|
||||||
|
|
|
@ -6,4 +6,43 @@ nonNumeric=باید عددی باشد
|
||||||
duplicateFormSubmission=ارسال تکراری فرم مجاز نیست
|
duplicateFormSubmission=ارسال تکراری فرم مجاز نیست
|
||||||
typeMismatch.date=تاریخ نامعتبر
|
typeMismatch.date=تاریخ نامعتبر
|
||||||
typeMismatch.birthDate=تاریخ تولد نامعتبر
|
typeMismatch.birthDate=تاریخ تولد نامعتبر
|
||||||
|
owner=مالک
|
||||||
|
firstName=نام
|
||||||
|
lastName=نام خانوادگی
|
||||||
|
address=آدرس
|
||||||
|
city=شهر
|
||||||
|
telephone=تلفن
|
||||||
|
owners=مالکان
|
||||||
|
addOwner=افزودن مالک
|
||||||
|
findOwner=یافتن مالک
|
||||||
|
findOwners=یافتن مالکان
|
||||||
|
updateOwner=ویرایش مالک
|
||||||
|
vets=دامپزشکان
|
||||||
|
name=نام
|
||||||
|
specialties=تخصصها
|
||||||
|
none=هیچکدام
|
||||||
|
pages=صفحات
|
||||||
|
first=اول
|
||||||
|
next=بعدی
|
||||||
|
previous=قبلی
|
||||||
|
last=آخر
|
||||||
|
somethingHappened=مشکلی پیش آمد...
|
||||||
|
pets=حیوانات خانگی
|
||||||
|
home=خانه
|
||||||
|
error=خطا
|
||||||
|
telephone.invalid=شماره تلفن باید ۱۰ رقمی باشد
|
||||||
|
layoutTitle=PetClinic :: یک نمایش از Spring Framework
|
||||||
|
pet=حیوان خانگی
|
||||||
|
birthDate=تاریخ تولد
|
||||||
|
type=نوع
|
||||||
|
previousVisits=ویزیتهای قبلی
|
||||||
|
date=تاریخ
|
||||||
|
description=توضیحات
|
||||||
|
new=جدید
|
||||||
|
addVisit=افزودن ویزیت
|
||||||
|
editPet=ویرایش حیوان خانگی
|
||||||
|
ownerInformation=اطلاعات مالک
|
||||||
|
visitDate=تاریخ ویزیت
|
||||||
|
editOwner=ویرایش مالک
|
||||||
|
addNewPet=افزودن حیوان خانگی جدید
|
||||||
|
petsAndVisits=حیوانات و ویزیتها
|
||||||
|
|
|
@ -6,3 +6,43 @@ nonNumeric=모두 숫자로 입력해야 합니다
|
||||||
duplicateFormSubmission=중복 제출은 허용되지 않습니다
|
duplicateFormSubmission=중복 제출은 허용되지 않습니다
|
||||||
typeMismatch.date=잘못된 날짜입니다
|
typeMismatch.date=잘못된 날짜입니다
|
||||||
typeMismatch.birthDate=잘못된 날짜입니다
|
typeMismatch.birthDate=잘못된 날짜입니다
|
||||||
|
owner=소유자
|
||||||
|
firstName=이름
|
||||||
|
lastName=성
|
||||||
|
address=주소
|
||||||
|
city=도시
|
||||||
|
telephone=전화번호
|
||||||
|
owners=소유자 목록
|
||||||
|
addOwner=소유자 추가
|
||||||
|
findOwner=소유자 찾기
|
||||||
|
findOwners=소유자들 찾기
|
||||||
|
updateOwner=소유자 수정
|
||||||
|
vets=수의사
|
||||||
|
name=이름
|
||||||
|
specialties=전문 분야
|
||||||
|
none=없음
|
||||||
|
pages=페이지
|
||||||
|
first=첫 번째
|
||||||
|
next=다음
|
||||||
|
previous=이전
|
||||||
|
last=마지막
|
||||||
|
somethingHappened=문제가 발생했습니다...
|
||||||
|
pets=반려동물
|
||||||
|
home=홈
|
||||||
|
error=오류
|
||||||
|
telephone.invalid=전화번호는 10자리 숫자여야 합니다
|
||||||
|
layoutTitle=PetClinic :: Spring Framework 데모
|
||||||
|
pet=반려동물
|
||||||
|
birthDate=생년월일
|
||||||
|
type=종류
|
||||||
|
previousVisits=이전 방문
|
||||||
|
date=날짜
|
||||||
|
description=설명
|
||||||
|
new=새로운
|
||||||
|
addVisit=방문 추가
|
||||||
|
editPet=반려동물 수정
|
||||||
|
ownerInformation=소유자 정보
|
||||||
|
visitDate=방문 날짜
|
||||||
|
editOwner=소유자 수정
|
||||||
|
addNewPet=새 반려동물 추가
|
||||||
|
petsAndVisits=반려동물 및 방문
|
||||||
|
|
|
@ -6,3 +6,43 @@ nonNumeric=Deve ser tudo numerico
|
||||||
duplicateFormSubmission=O envio duplicado de formulario nao e permitido
|
duplicateFormSubmission=O envio duplicado de formulario nao e permitido
|
||||||
typeMismatch.date=Data invalida
|
typeMismatch.date=Data invalida
|
||||||
typeMismatch.birthDate=Data de nascimento invalida
|
typeMismatch.birthDate=Data de nascimento invalida
|
||||||
|
owner=Proprietário
|
||||||
|
firstName=Primeiro Nome
|
||||||
|
lastName=Sobrenome
|
||||||
|
address=Endereço
|
||||||
|
city=Cidade
|
||||||
|
telephone=Telefone
|
||||||
|
owners=Proprietários
|
||||||
|
addOwner=Adicionar proprietário
|
||||||
|
findOwner=Encontrar proprietário
|
||||||
|
findOwners=Encontrar proprietários
|
||||||
|
updateOwner=Atualizar proprietário
|
||||||
|
vets=Veterinários
|
||||||
|
name=Nome
|
||||||
|
specialties=Especialidades
|
||||||
|
none=nenhum
|
||||||
|
pages=páginas
|
||||||
|
first=Primeiro
|
||||||
|
next=Próximo
|
||||||
|
previous=Anterior
|
||||||
|
last=Último
|
||||||
|
somethingHappened=Algo aconteceu...
|
||||||
|
pets=Animais de estimação
|
||||||
|
home=Início
|
||||||
|
error=Erro
|
||||||
|
telephone.invalid=O número de telefone deve conter 10 dígitos
|
||||||
|
layoutTitle=PetClinic :: uma demonstração do Spring Framework
|
||||||
|
pet=Animal de estimação
|
||||||
|
birthDate=Data de nascimento
|
||||||
|
type=Tipo
|
||||||
|
previousVisits=Visitas anteriores
|
||||||
|
date=Data
|
||||||
|
description=Descrição
|
||||||
|
new=Novo
|
||||||
|
addVisit=Adicionar visita
|
||||||
|
editPet=Editar animal
|
||||||
|
ownerInformation=Informações do proprietário
|
||||||
|
visitDate=Data da visita
|
||||||
|
editOwner=Editar proprietário
|
||||||
|
addNewPet=Adicionar novo animal
|
||||||
|
petsAndVisits=Animais e visitas
|
||||||
|
|
|
@ -6,4 +6,43 @@ nonNumeric=должно быть все числовое значение
|
||||||
duplicateFormSubmission=Дублирование формы не допускается
|
duplicateFormSubmission=Дублирование формы не допускается
|
||||||
typeMismatch.date=неправильная даные
|
typeMismatch.date=неправильная даные
|
||||||
typeMismatch.birthDate=неправильная дата
|
typeMismatch.birthDate=неправильная дата
|
||||||
|
owner=Владелец
|
||||||
|
firstName=Имя
|
||||||
|
lastName=Фамилия
|
||||||
|
address=Адрес
|
||||||
|
city=Город
|
||||||
|
telephone=Телефон
|
||||||
|
owners=Владельцы
|
||||||
|
addOwner=Добавить владельца
|
||||||
|
findOwner=Найти владельца
|
||||||
|
findOwners=Найти владельцев
|
||||||
|
updateOwner=Обновить владельца
|
||||||
|
vets=Ветеринары
|
||||||
|
name=Имя
|
||||||
|
specialties=Специальности
|
||||||
|
none=нет
|
||||||
|
pages=страницы
|
||||||
|
first=Первый
|
||||||
|
next=Следующий
|
||||||
|
previous=Предыдущий
|
||||||
|
last=Последний
|
||||||
|
somethingHappened=Что-то пошло не так...
|
||||||
|
pets=Питомцы
|
||||||
|
home=Главная
|
||||||
|
error=Ошибка
|
||||||
|
telephone.invalid=Телефон должен содержать 10 цифр
|
||||||
|
layoutTitle=PetClinic :: демонстрация Spring Framework
|
||||||
|
pet=Питомец
|
||||||
|
birthDate=Дата рождения
|
||||||
|
type=Тип
|
||||||
|
previousVisits=Предыдущие визиты
|
||||||
|
date=Дата
|
||||||
|
description=Описание
|
||||||
|
new=Новый
|
||||||
|
addVisit=Добавить визит
|
||||||
|
editPet=Редактировать питомца
|
||||||
|
ownerInformation=Информация о владельце
|
||||||
|
visitDate=Дата визита
|
||||||
|
editOwner=Редактировать владельца
|
||||||
|
addNewPet=Добавить нового питомца
|
||||||
|
petsAndVisits=Питомцы и визиты
|
||||||
|
|
|
@ -6,4 +6,43 @@ nonNumeric=sadece sayısal olmalıdır
|
||||||
duplicateFormSubmission=Formun tekrar gönderilmesine izin verilmez
|
duplicateFormSubmission=Formun tekrar gönderilmesine izin verilmez
|
||||||
typeMismatch.date=geçersiz tarih
|
typeMismatch.date=geçersiz tarih
|
||||||
typeMismatch.birthDate=geçersiz tarih
|
typeMismatch.birthDate=geçersiz tarih
|
||||||
|
owner=Sahip
|
||||||
|
firstName=Ad
|
||||||
|
lastName=Soyad
|
||||||
|
address=Adres
|
||||||
|
city=Şehir
|
||||||
|
telephone=Telefon
|
||||||
|
owners=Sahipler
|
||||||
|
addOwner=Sahip Ekle
|
||||||
|
findOwner=Sahip Bul
|
||||||
|
findOwners=Sahipleri Bul
|
||||||
|
updateOwner=Sahip Güncelle
|
||||||
|
vets=Veterinerler
|
||||||
|
name=İsim
|
||||||
|
specialties=Uzmanlıklar
|
||||||
|
none=yok
|
||||||
|
pages=sayfalar
|
||||||
|
first=İlk
|
||||||
|
next=Sonraki
|
||||||
|
previous=Önceki
|
||||||
|
last=Son
|
||||||
|
somethingHappened=Bir şey oldu...
|
||||||
|
pets=Evcil Hayvanlar
|
||||||
|
home=Ana Sayfa
|
||||||
|
error=Hata
|
||||||
|
telephone.invalid=Telefon numarası 10 basamaklı olmalıdır
|
||||||
|
layoutTitle=PetClinic :: bir Spring Framework demosu
|
||||||
|
pet=Evcil Hayvan
|
||||||
|
birthDate=Doğum Tarihi
|
||||||
|
type=Tür
|
||||||
|
previousVisits=Önceki Ziyaretler
|
||||||
|
date=Tarih
|
||||||
|
description=Açıklama
|
||||||
|
new=Yeni
|
||||||
|
addVisit=Ziyaret Ekle
|
||||||
|
editPet=Evcil Hayvanı Düzenle
|
||||||
|
ownerInformation=Sahip Bilgileri
|
||||||
|
visitDate=Ziyaret Tarihi
|
||||||
|
editOwner=Sahibi Düzenle
|
||||||
|
addNewPet=Yeni Evcil Hayvan Ekle
|
||||||
|
petsAndVisits=Evcil Hayvanlar ve Ziyaretler
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
/*!
|
/*!
|
||||||
* Bootstrap v5.3.3 (https://getbootstrap.com/)
|
* Bootstrap v5.3.6 (https://getbootstrap.com/)
|
||||||
* Copyright 2011-2024 The Bootstrap Authors
|
* Copyright 2011-2025 The Bootstrap Authors
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||||
*/
|
*/
|
||||||
:root,
|
:root,
|
||||||
|
@ -456,8 +456,8 @@ legend {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
font-size: calc(1.275rem + 0.3vw);
|
line-height: inherit;
|
||||||
line-height: inherit; }
|
font-size: calc(1.275rem + 0.3vw); }
|
||||||
@media (min-width: 1200px) {
|
@media (min-width: 1200px) {
|
||||||
legend {
|
legend {
|
||||||
font-size: 1.5rem; } }
|
font-size: 1.5rem; } }
|
||||||
|
@ -519,44 +519,44 @@ progress {
|
||||||
font-weight: 300; }
|
font-weight: 300; }
|
||||||
|
|
||||||
.display-1 {
|
.display-1 {
|
||||||
font-size: calc(1.625rem + 4.5vw);
|
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
line-height: 1.2; }
|
line-height: 1.2;
|
||||||
|
font-size: calc(1.625rem + 4.5vw); }
|
||||||
@media (min-width: 1200px) {
|
@media (min-width: 1200px) {
|
||||||
.display-1 {
|
.display-1 {
|
||||||
font-size: 5rem; } }
|
font-size: 5rem; } }
|
||||||
.display-2 {
|
.display-2 {
|
||||||
font-size: calc(1.575rem + 3.9vw);
|
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
line-height: 1.2; }
|
line-height: 1.2;
|
||||||
|
font-size: calc(1.575rem + 3.9vw); }
|
||||||
@media (min-width: 1200px) {
|
@media (min-width: 1200px) {
|
||||||
.display-2 {
|
.display-2 {
|
||||||
font-size: 4.5rem; } }
|
font-size: 4.5rem; } }
|
||||||
.display-3 {
|
.display-3 {
|
||||||
font-size: calc(1.525rem + 3.3vw);
|
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
line-height: 1.2; }
|
line-height: 1.2;
|
||||||
|
font-size: calc(1.525rem + 3.3vw); }
|
||||||
@media (min-width: 1200px) {
|
@media (min-width: 1200px) {
|
||||||
.display-3 {
|
.display-3 {
|
||||||
font-size: 4rem; } }
|
font-size: 4rem; } }
|
||||||
.display-4 {
|
.display-4 {
|
||||||
font-size: calc(1.475rem + 2.7vw);
|
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
line-height: 1.2; }
|
line-height: 1.2;
|
||||||
|
font-size: calc(1.475rem + 2.7vw); }
|
||||||
@media (min-width: 1200px) {
|
@media (min-width: 1200px) {
|
||||||
.display-4 {
|
.display-4 {
|
||||||
font-size: 3.5rem; } }
|
font-size: 3.5rem; } }
|
||||||
.display-5 {
|
.display-5 {
|
||||||
font-size: calc(1.425rem + 2.1vw);
|
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
line-height: 1.2; }
|
line-height: 1.2;
|
||||||
|
font-size: calc(1.425rem + 2.1vw); }
|
||||||
@media (min-width: 1200px) {
|
@media (min-width: 1200px) {
|
||||||
.display-5 {
|
.display-5 {
|
||||||
font-size: 3rem; } }
|
font-size: 3rem; } }
|
||||||
.display-6 {
|
.display-6 {
|
||||||
font-size: calc(1.375rem + 1.5vw);
|
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
line-height: 1.2; }
|
line-height: 1.2;
|
||||||
|
font-size: calc(1.375rem + 1.5vw); }
|
||||||
@media (min-width: 1200px) {
|
@media (min-width: 1200px) {
|
||||||
.display-6 {
|
.display-6 {
|
||||||
font-size: 2.5rem; } }
|
font-size: 2.5rem; } }
|
||||||
|
@ -674,7 +674,7 @@ progress {
|
||||||
margin-top: var(--bs-gutter-y); }
|
margin-top: var(--bs-gutter-y); }
|
||||||
|
|
||||||
.col {
|
.col {
|
||||||
flex: 1 0 0%; }
|
flex: 1 0 0; }
|
||||||
|
|
||||||
.row-cols-auto > * {
|
.row-cols-auto > * {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
@ -839,7 +839,7 @@ progress {
|
||||||
|
|
||||||
@media (min-width: 576px) {
|
@media (min-width: 576px) {
|
||||||
.col-sm {
|
.col-sm {
|
||||||
flex: 1 0 0%; }
|
flex: 1 0 0; }
|
||||||
.row-cols-sm-auto > * {
|
.row-cols-sm-auto > * {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
width: auto; }
|
width: auto; }
|
||||||
|
@ -963,7 +963,7 @@ progress {
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
.col-md {
|
.col-md {
|
||||||
flex: 1 0 0%; }
|
flex: 1 0 0; }
|
||||||
.row-cols-md-auto > * {
|
.row-cols-md-auto > * {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
width: auto; }
|
width: auto; }
|
||||||
|
@ -1087,7 +1087,7 @@ progress {
|
||||||
|
|
||||||
@media (min-width: 992px) {
|
@media (min-width: 992px) {
|
||||||
.col-lg {
|
.col-lg {
|
||||||
flex: 1 0 0%; }
|
flex: 1 0 0; }
|
||||||
.row-cols-lg-auto > * {
|
.row-cols-lg-auto > * {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
width: auto; }
|
width: auto; }
|
||||||
|
@ -1211,7 +1211,7 @@ progress {
|
||||||
|
|
||||||
@media (min-width: 1200px) {
|
@media (min-width: 1200px) {
|
||||||
.col-xl {
|
.col-xl {
|
||||||
flex: 1 0 0%; }
|
flex: 1 0 0; }
|
||||||
.row-cols-xl-auto > * {
|
.row-cols-xl-auto > * {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
width: auto; }
|
width: auto; }
|
||||||
|
@ -1335,7 +1335,7 @@ progress {
|
||||||
|
|
||||||
@media (min-width: 1400px) {
|
@media (min-width: 1400px) {
|
||||||
.col-xxl {
|
.col-xxl {
|
||||||
flex: 1 0 0%; }
|
flex: 1 0 0; }
|
||||||
.row-cols-xxl-auto > * {
|
.row-cols-xxl-auto > * {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
width: auto; }
|
width: auto; }
|
||||||
|
@ -1899,9 +1899,9 @@ textarea.form-control-lg {
|
||||||
.form-check-input:checked {
|
.form-check-input:checked {
|
||||||
background-color: #0d6efd;
|
background-color: #0d6efd;
|
||||||
border-color: #0d6efd; }
|
border-color: #0d6efd; }
|
||||||
.form-check-input[type="checkbox"]:checked {
|
.form-check-input:checked[type="checkbox"] {
|
||||||
--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e"); }
|
--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e"); }
|
||||||
.form-check-input[type="radio"]:checked {
|
.form-check-input:checked[type="radio"] {
|
||||||
--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e"); }
|
--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e"); }
|
||||||
.form-check-input[type="checkbox"]:indeterminate {
|
.form-check-input[type="checkbox"]:indeterminate {
|
||||||
background-color: #0d6efd;
|
background-color: #0d6efd;
|
||||||
|
@ -2033,9 +2033,11 @@ textarea.form-control-lg {
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
max-width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 1rem 0.75rem;
|
padding: 1rem 0.75rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
color: rgba(var(--bs-body-color-rgb), 0.65);
|
||||||
text-align: start;
|
text-align: start;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
@ -2063,17 +2065,17 @@ textarea.form-control-lg {
|
||||||
padding-bottom: 0.625rem; }
|
padding-bottom: 0.625rem; }
|
||||||
.form-floating > .form-select {
|
.form-floating > .form-select {
|
||||||
padding-top: 1.625rem;
|
padding-top: 1.625rem;
|
||||||
padding-bottom: 0.625rem; }
|
padding-bottom: 0.625rem;
|
||||||
|
padding-left: 0.75rem; }
|
||||||
.form-floating > .form-control:focus ~ label,
|
.form-floating > .form-control:focus ~ label,
|
||||||
.form-floating > .form-control:not(:placeholder-shown) ~ label,
|
.form-floating > .form-control:not(:placeholder-shown) ~ label,
|
||||||
.form-floating > .form-control-plaintext ~ label,
|
.form-floating > .form-control-plaintext ~ label,
|
||||||
.form-floating > .form-select ~ label {
|
.form-floating > .form-select ~ label {
|
||||||
color: rgba(var(--bs-body-color-rgb), 0.65);
|
|
||||||
transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem); }
|
transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem); }
|
||||||
.form-floating > .form-control:focus ~ label::after,
|
.form-floating > .form-control:-webkit-autofill ~ label {
|
||||||
.form-floating > .form-control:not(:placeholder-shown) ~ label::after,
|
transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem); }
|
||||||
.form-floating > .form-control-plaintext ~ label::after,
|
.form-floating > textarea:focus ~ label::after,
|
||||||
.form-floating > .form-select ~ label::after {
|
.form-floating > textarea:not(:placeholder-shown) ~ label::after {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 1rem 0.375rem;
|
inset: 1rem 0.375rem;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
|
@ -2081,17 +2083,13 @@ textarea.form-control-lg {
|
||||||
content: "";
|
content: "";
|
||||||
background-color: var(--bs-body-bg);
|
background-color: var(--bs-body-bg);
|
||||||
border-radius: var(--bs-border-radius); }
|
border-radius: var(--bs-border-radius); }
|
||||||
.form-floating > .form-control:-webkit-autofill ~ label {
|
.form-floating > textarea:disabled ~ label::after {
|
||||||
color: rgba(var(--bs-body-color-rgb), 0.65);
|
background-color: var(--bs-secondary-bg); }
|
||||||
transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem); }
|
|
||||||
.form-floating > .form-control-plaintext ~ label {
|
.form-floating > .form-control-plaintext ~ label {
|
||||||
border-width: var(--bs-border-width) 0; }
|
border-width: var(--bs-border-width) 0; }
|
||||||
.form-floating > :disabled ~ label,
|
.form-floating > :disabled ~ label,
|
||||||
.form-floating > .form-control:disabled ~ label {
|
.form-floating > .form-control:disabled ~ label {
|
||||||
color: #6c757d; }
|
color: #6c757d; }
|
||||||
.form-floating > :disabled ~ label::after,
|
|
||||||
.form-floating > .form-control:disabled ~ label::after {
|
|
||||||
background-color: var(--bs-secondary-bg); }
|
|
||||||
|
|
||||||
.input-group {
|
.input-group {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -2165,7 +2163,7 @@ textarea.form-control-lg {
|
||||||
border-bottom-right-radius: 0; }
|
border-bottom-right-radius: 0; }
|
||||||
|
|
||||||
.input-group > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) {
|
.input-group > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) {
|
||||||
margin-left: calc(var(--bs-border-width) * -1);
|
margin-left: calc(-1 * var(--bs-border-width));
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
border-bottom-left-radius: 0; }
|
border-bottom-left-radius: 0; }
|
||||||
|
|
||||||
|
@ -2203,7 +2201,7 @@ textarea.form-control-lg {
|
||||||
.was-validated .form-control:valid, .form-control.is-valid {
|
.was-validated .form-control:valid, .form-control.is-valid {
|
||||||
border-color: var(--bs-form-valid-border-color);
|
border-color: var(--bs-form-valid-border-color);
|
||||||
padding-right: calc(1.5em + 0.75rem);
|
padding-right: calc(1.5em + 0.75rem);
|
||||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
|
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1'/%3e%3c/svg%3e");
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: right calc(0.375em + 0.1875rem) center;
|
background-position: right calc(0.375em + 0.1875rem) center;
|
||||||
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); }
|
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); }
|
||||||
|
@ -2217,8 +2215,8 @@ textarea.form-control-lg {
|
||||||
|
|
||||||
.was-validated .form-select:valid, .form-select.is-valid {
|
.was-validated .form-select:valid, .form-select.is-valid {
|
||||||
border-color: var(--bs-form-valid-border-color); }
|
border-color: var(--bs-form-valid-border-color); }
|
||||||
.was-validated .form-select:valid:not([multiple]):not([size]), .was-validated .form-select[size="1"]:valid:not([multiple]), .form-select.is-valid:not([multiple]):not([size]), .form-select.is-valid[size="1"]:not([multiple]) {
|
.was-validated .form-select:valid:not([multiple]):not([size]), .was-validated .form-select:valid:not([multiple])[size="1"], .form-select.is-valid:not([multiple]):not([size]), .form-select.is-valid:not([multiple])[size="1"] {
|
||||||
--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
|
--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1'/%3e%3c/svg%3e");
|
||||||
padding-right: 4.125rem;
|
padding-right: 4.125rem;
|
||||||
background-position: right 0.75rem center, center right 2.25rem;
|
background-position: right 0.75rem center, center right 2.25rem;
|
||||||
background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); }
|
background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); }
|
||||||
|
@ -2241,9 +2239,9 @@ textarea.form-control-lg {
|
||||||
.form-check-inline .form-check-input ~ .valid-feedback {
|
.form-check-inline .form-check-input ~ .valid-feedback {
|
||||||
margin-left: .5em; }
|
margin-left: .5em; }
|
||||||
|
|
||||||
.was-validated .input-group > .form-control:not(:focus):valid, .input-group > .form-control.is-valid:not(:focus), .was-validated .input-group > .form-select:not(:focus):valid,
|
.was-validated .input-group > .form-control:not(:focus):valid, .input-group > .form-control:not(:focus).is-valid, .was-validated .input-group > .form-select:not(:focus):valid,
|
||||||
.input-group > .form-select.is-valid:not(:focus), .was-validated .input-group > .form-floating:not(:focus-within):valid,
|
.input-group > .form-select:not(:focus).is-valid, .was-validated .input-group > .form-floating:not(:focus-within):valid,
|
||||||
.input-group > .form-floating.is-valid:not(:focus-within) {
|
.input-group > .form-floating:not(:focus-within).is-valid {
|
||||||
z-index: 3; }
|
z-index: 3; }
|
||||||
|
|
||||||
.invalid-feedback {
|
.invalid-feedback {
|
||||||
|
@ -2289,7 +2287,7 @@ textarea.form-control-lg {
|
||||||
|
|
||||||
.was-validated .form-select:invalid, .form-select.is-invalid {
|
.was-validated .form-select:invalid, .form-select.is-invalid {
|
||||||
border-color: var(--bs-form-invalid-border-color); }
|
border-color: var(--bs-form-invalid-border-color); }
|
||||||
.was-validated .form-select:invalid:not([multiple]):not([size]), .was-validated .form-select[size="1"]:invalid:not([multiple]), .form-select.is-invalid:not([multiple]):not([size]), .form-select.is-invalid[size="1"]:not([multiple]) {
|
.was-validated .form-select:invalid:not([multiple]):not([size]), .was-validated .form-select:invalid:not([multiple])[size="1"], .form-select.is-invalid:not([multiple]):not([size]), .form-select.is-invalid:not([multiple])[size="1"] {
|
||||||
--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
|
--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
|
||||||
padding-right: 4.125rem;
|
padding-right: 4.125rem;
|
||||||
background-position: right 0.75rem center, center right 2.25rem;
|
background-position: right 0.75rem center, center right 2.25rem;
|
||||||
|
@ -2313,9 +2311,9 @@ textarea.form-control-lg {
|
||||||
.form-check-inline .form-check-input ~ .invalid-feedback {
|
.form-check-inline .form-check-input ~ .invalid-feedback {
|
||||||
margin-left: .5em; }
|
margin-left: .5em; }
|
||||||
|
|
||||||
.was-validated .input-group > .form-control:not(:focus):invalid, .input-group > .form-control.is-invalid:not(:focus), .was-validated .input-group > .form-select:not(:focus):invalid,
|
.was-validated .input-group > .form-control:not(:focus):invalid, .input-group > .form-control:not(:focus).is-invalid, .was-validated .input-group > .form-select:not(:focus):invalid,
|
||||||
.input-group > .form-select.is-invalid:not(:focus), .was-validated .input-group > .form-floating:not(:focus-within):invalid,
|
.input-group > .form-select:not(:focus).is-invalid, .was-validated .input-group > .form-floating:not(:focus-within):invalid,
|
||||||
.input-group > .form-floating.is-invalid:not(:focus-within) {
|
.input-group > .form-floating:not(:focus-within).is-invalid {
|
||||||
z-index: 4; }
|
z-index: 4; }
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
|
@ -3007,7 +3005,7 @@ textarea.form-control-lg {
|
||||||
border-radius: var(--bs-border-radius); }
|
border-radius: var(--bs-border-radius); }
|
||||||
.btn-group > :not(.btn-check:first-child) + .btn,
|
.btn-group > :not(.btn-check:first-child) + .btn,
|
||||||
.btn-group > .btn-group:not(:first-child) {
|
.btn-group > .btn-group:not(:first-child) {
|
||||||
margin-left: calc(var(--bs-border-width) * -1); }
|
margin-left: calc(-1 * var(--bs-border-width)); }
|
||||||
.btn-group > .btn:not(:last-child):not(.dropdown-toggle),
|
.btn-group > .btn:not(:last-child):not(.dropdown-toggle),
|
||||||
.btn-group > .btn.dropdown-toggle-split:first-child,
|
.btn-group > .btn.dropdown-toggle-split:first-child,
|
||||||
.btn-group > .btn-group:not(:last-child) > .btn {
|
.btn-group > .btn-group:not(:last-child) > .btn {
|
||||||
|
@ -3044,12 +3042,13 @@ textarea.form-control-lg {
|
||||||
width: 100%; }
|
width: 100%; }
|
||||||
.btn-group-vertical > .btn:not(:first-child),
|
.btn-group-vertical > .btn:not(:first-child),
|
||||||
.btn-group-vertical > .btn-group:not(:first-child) {
|
.btn-group-vertical > .btn-group:not(:first-child) {
|
||||||
margin-top: calc(var(--bs-border-width) * -1); }
|
margin-top: calc(-1 * var(--bs-border-width)); }
|
||||||
.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle),
|
.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle),
|
||||||
.btn-group-vertical > .btn-group:not(:last-child) > .btn {
|
.btn-group-vertical > .btn-group:not(:last-child) > .btn {
|
||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
border-bottom-left-radius: 0; }
|
border-bottom-left-radius: 0; }
|
||||||
.btn-group-vertical > .btn ~ .btn,
|
.btn-group-vertical > .btn:nth-child(n + 3),
|
||||||
|
.btn-group-vertical > :not(.btn-check) + .btn,
|
||||||
.btn-group-vertical > .btn-group:not(:first-child) > .btn {
|
.btn-group-vertical > .btn-group:not(:first-child) > .btn {
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
border-top-right-radius: 0; }
|
border-top-right-radius: 0; }
|
||||||
|
@ -3152,8 +3151,8 @@ textarea.form-control-lg {
|
||||||
|
|
||||||
.nav-justified > .nav-link,
|
.nav-justified > .nav-link,
|
||||||
.nav-justified .nav-item {
|
.nav-justified .nav-item {
|
||||||
flex-basis: 0;
|
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
flex-basis: 0;
|
||||||
text-align: center; }
|
text-align: center; }
|
||||||
|
|
||||||
.nav-fill .nav-item .nav-link,
|
.nav-fill .nav-item .nav-link,
|
||||||
|
@ -3243,8 +3242,8 @@ textarea.form-control-lg {
|
||||||
color: var(--bs-navbar-active-color); }
|
color: var(--bs-navbar-active-color); }
|
||||||
|
|
||||||
.navbar-collapse {
|
.navbar-collapse {
|
||||||
flex-basis: 100%;
|
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
flex-basis: 100%;
|
||||||
align-items: center; }
|
align-items: center; }
|
||||||
|
|
||||||
.navbar-toggler {
|
.navbar-toggler {
|
||||||
|
@ -3646,7 +3645,7 @@ textarea.form-control-lg {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: row wrap; }
|
flex-flow: row wrap; }
|
||||||
.card-group > .card {
|
.card-group > .card {
|
||||||
flex: 1 0 0%;
|
flex: 1 0 0;
|
||||||
margin-bottom: 0; }
|
margin-bottom: 0; }
|
||||||
.card-group > .card + .card {
|
.card-group > .card + .card {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
|
@ -3654,20 +3653,20 @@ textarea.form-control-lg {
|
||||||
.card-group > .card:not(:last-child) {
|
.card-group > .card:not(:last-child) {
|
||||||
border-top-right-radius: 0;
|
border-top-right-radius: 0;
|
||||||
border-bottom-right-radius: 0; }
|
border-bottom-right-radius: 0; }
|
||||||
.card-group > .card:not(:last-child) .card-img-top,
|
.card-group > .card:not(:last-child) > .card-img-top,
|
||||||
.card-group > .card:not(:last-child) .card-header {
|
.card-group > .card:not(:last-child) > .card-header {
|
||||||
border-top-right-radius: 0; }
|
border-top-right-radius: 0; }
|
||||||
.card-group > .card:not(:last-child) .card-img-bottom,
|
.card-group > .card:not(:last-child) > .card-img-bottom,
|
||||||
.card-group > .card:not(:last-child) .card-footer {
|
.card-group > .card:not(:last-child) > .card-footer {
|
||||||
border-bottom-right-radius: 0; }
|
border-bottom-right-radius: 0; }
|
||||||
.card-group > .card:not(:first-child) {
|
.card-group > .card:not(:first-child) {
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
border-bottom-left-radius: 0; }
|
border-bottom-left-radius: 0; }
|
||||||
.card-group > .card:not(:first-child) .card-img-top,
|
.card-group > .card:not(:first-child) > .card-img-top,
|
||||||
.card-group > .card:not(:first-child) .card-header {
|
.card-group > .card:not(:first-child) > .card-header {
|
||||||
border-top-left-radius: 0; }
|
border-top-left-radius: 0; }
|
||||||
.card-group > .card:not(:first-child) .card-img-bottom,
|
.card-group > .card:not(:first-child) > .card-img-bottom,
|
||||||
.card-group > .card:not(:first-child) .card-footer {
|
.card-group > .card:not(:first-child) > .card-footer {
|
||||||
border-bottom-left-radius: 0; } }
|
border-bottom-left-radius: 0; } }
|
||||||
|
|
||||||
.accordion {
|
.accordion {
|
||||||
|
@ -3682,11 +3681,11 @@ textarea.form-control-lg {
|
||||||
--bs-accordion-btn-padding-y: 1rem;
|
--bs-accordion-btn-padding-y: 1rem;
|
||||||
--bs-accordion-btn-color: var(--bs-body-color);
|
--bs-accordion-btn-color: var(--bs-body-color);
|
||||||
--bs-accordion-btn-bg: var(--bs-accordion-bg);
|
--bs-accordion-btn-bg: var(--bs-accordion-bg);
|
||||||
--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23212529' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");
|
--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23212529' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
|
||||||
--bs-accordion-btn-icon-width: 1.25rem;
|
--bs-accordion-btn-icon-width: 1.25rem;
|
||||||
--bs-accordion-btn-icon-transform: rotate(-180deg);
|
--bs-accordion-btn-icon-transform: rotate(-180deg);
|
||||||
--bs-accordion-btn-icon-transition: transform 0.2s ease-in-out;
|
--bs-accordion-btn-icon-transition: transform 0.2s ease-in-out;
|
||||||
--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23052c65' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");
|
--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23052c65' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
|
||||||
--bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
|
--bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
|
||||||
--bs-accordion-body-padding-x: 1.25rem;
|
--bs-accordion-body-padding-x: 1.25rem;
|
||||||
--bs-accordion-body-padding-y: 1rem;
|
--bs-accordion-body-padding-y: 1rem;
|
||||||
|
@ -3773,14 +3772,14 @@ textarea.form-control-lg {
|
||||||
border-top: 0; }
|
border-top: 0; }
|
||||||
.accordion-flush > .accordion-item:last-child {
|
.accordion-flush > .accordion-item:last-child {
|
||||||
border-bottom: 0; }
|
border-bottom: 0; }
|
||||||
.accordion-flush > .accordion-item > .accordion-header .accordion-button, .accordion-flush > .accordion-item > .accordion-header .accordion-button.collapsed {
|
.accordion-flush > .accordion-item > .accordion-collapse,
|
||||||
border-radius: 0; }
|
.accordion-flush > .accordion-item > .accordion-header .accordion-button,
|
||||||
.accordion-flush > .accordion-item > .accordion-collapse {
|
.accordion-flush > .accordion-item > .accordion-header .accordion-button.collapsed {
|
||||||
border-radius: 0; }
|
border-radius: 0; }
|
||||||
|
|
||||||
[data-bs-theme="dark"] .accordion-button::after {
|
[data-bs-theme="dark"] .accordion-button::after {
|
||||||
--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
|
--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708'/%3e%3c/svg%3e");
|
||||||
--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); }
|
--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708'/%3e%3c/svg%3e"); }
|
||||||
|
|
||||||
.breadcrumb {
|
.breadcrumb {
|
||||||
--bs-breadcrumb-padding-x: 0;
|
--bs-breadcrumb-padding-x: 0;
|
||||||
|
@ -3872,7 +3871,7 @@ textarea.form-control-lg {
|
||||||
border-color: var(--bs-pagination-disabled-border-color); }
|
border-color: var(--bs-pagination-disabled-border-color); }
|
||||||
|
|
||||||
.page-item:not(:first-child) .page-link {
|
.page-item:not(:first-child) .page-link {
|
||||||
margin-left: calc(var(--bs-border-width) * -1); }
|
margin-left: calc(-1 * var(--bs-border-width)); }
|
||||||
|
|
||||||
.page-item:first-child .page-link {
|
.page-item:first-child .page-link {
|
||||||
border-top-left-radius: var(--bs-pagination-border-radius);
|
border-top-left-radius: var(--bs-pagination-border-radius);
|
||||||
|
@ -4002,7 +4001,7 @@ textarea.form-control-lg {
|
||||||
|
|
||||||
@keyframes progress-bar-stripes {
|
@keyframes progress-bar-stripes {
|
||||||
0% {
|
0% {
|
||||||
background-position-x: 1rem; } }
|
background-position-x: var(--bs-progress-height); } }
|
||||||
|
|
||||||
.progress,
|
.progress,
|
||||||
.progress-stacked {
|
.progress-stacked {
|
||||||
|
@ -4080,19 +4079,6 @@ textarea.form-control-lg {
|
||||||
content: counters(section, ".") ". ";
|
content: counters(section, ".") ". ";
|
||||||
counter-increment: section; }
|
counter-increment: section; }
|
||||||
|
|
||||||
.list-group-item-action {
|
|
||||||
width: 100%;
|
|
||||||
color: var(--bs-list-group-action-color);
|
|
||||||
text-align: inherit; }
|
|
||||||
.list-group-item-action:hover, .list-group-item-action:focus {
|
|
||||||
z-index: 1;
|
|
||||||
color: var(--bs-list-group-action-hover-color);
|
|
||||||
text-decoration: none;
|
|
||||||
background-color: var(--bs-list-group-action-hover-bg); }
|
|
||||||
.list-group-item-action:active {
|
|
||||||
color: var(--bs-list-group-action-active-color);
|
|
||||||
background-color: var(--bs-list-group-action-active-bg); }
|
|
||||||
|
|
||||||
.list-group-item {
|
.list-group-item {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -4122,6 +4108,19 @@ textarea.form-control-lg {
|
||||||
margin-top: calc(-1 * var(--bs-list-group-border-width));
|
margin-top: calc(-1 * var(--bs-list-group-border-width));
|
||||||
border-top-width: var(--bs-list-group-border-width); }
|
border-top-width: var(--bs-list-group-border-width); }
|
||||||
|
|
||||||
|
.list-group-item-action {
|
||||||
|
width: 100%;
|
||||||
|
color: var(--bs-list-group-action-color);
|
||||||
|
text-align: inherit; }
|
||||||
|
.list-group-item-action:not(.active):hover, .list-group-item-action:not(.active):focus {
|
||||||
|
z-index: 1;
|
||||||
|
color: var(--bs-list-group-action-hover-color);
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: var(--bs-list-group-action-hover-bg); }
|
||||||
|
.list-group-item-action:not(.active):active {
|
||||||
|
color: var(--bs-list-group-action-active-color);
|
||||||
|
background-color: var(--bs-list-group-action-active-bg); }
|
||||||
|
|
||||||
.list-group-horizontal {
|
.list-group-horizontal {
|
||||||
flex-direction: row; }
|
flex-direction: row; }
|
||||||
.list-group-horizontal > .list-group-item:first-child:not(:last-child) {
|
.list-group-horizontal > .list-group-item:first-child:not(:last-child) {
|
||||||
|
@ -4334,19 +4333,19 @@ textarea.form-control-lg {
|
||||||
|
|
||||||
.btn-close {
|
.btn-close {
|
||||||
--bs-btn-close-color: #000;
|
--bs-btn-close-color: #000;
|
||||||
--bs-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");
|
--bs-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414'/%3e%3c/svg%3e");
|
||||||
--bs-btn-close-opacity: 0.5;
|
--bs-btn-close-opacity: 0.5;
|
||||||
--bs-btn-close-hover-opacity: 0.75;
|
--bs-btn-close-hover-opacity: 0.75;
|
||||||
--bs-btn-close-focus-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
|
--bs-btn-close-focus-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
|
||||||
--bs-btn-close-focus-opacity: 1;
|
--bs-btn-close-focus-opacity: 1;
|
||||||
--bs-btn-close-disabled-opacity: 0.25;
|
--bs-btn-close-disabled-opacity: 0.25;
|
||||||
--bs-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%);
|
|
||||||
box-sizing: content-box;
|
box-sizing: content-box;
|
||||||
width: 1em;
|
width: 1em;
|
||||||
height: 1em;
|
height: 1em;
|
||||||
padding: 0.25em 0.25em;
|
padding: 0.25em 0.25em;
|
||||||
color: var(--bs-btn-close-color);
|
color: var(--bs-btn-close-color);
|
||||||
background: transparent var(--bs-btn-close-bg) center/1em auto no-repeat;
|
background: transparent var(--bs-btn-close-bg) center/1em auto no-repeat;
|
||||||
|
filter: var(--bs-btn-close-filter);
|
||||||
border: 0;
|
border: 0;
|
||||||
border-radius: 0.375rem;
|
border-radius: 0.375rem;
|
||||||
opacity: var(--bs-btn-close-opacity); }
|
opacity: var(--bs-btn-close-opacity); }
|
||||||
|
@ -4364,10 +4363,14 @@ textarea.form-control-lg {
|
||||||
opacity: var(--bs-btn-close-disabled-opacity); }
|
opacity: var(--bs-btn-close-disabled-opacity); }
|
||||||
|
|
||||||
.btn-close-white {
|
.btn-close-white {
|
||||||
filter: var(--bs-btn-close-white-filter); }
|
--bs-btn-close-filter: invert(1) grayscale(100%) brightness(200%); }
|
||||||
|
|
||||||
[data-bs-theme="dark"] .btn-close {
|
:root,
|
||||||
filter: var(--bs-btn-close-white-filter); }
|
[data-bs-theme="light"] {
|
||||||
|
--bs-btn-close-filter: ; }
|
||||||
|
|
||||||
|
[data-bs-theme="dark"] {
|
||||||
|
--bs-btn-close-filter: invert(1) grayscale(100%) brightness(200%); }
|
||||||
|
|
||||||
.toast {
|
.toast {
|
||||||
--bs-toast-zindex: 1090;
|
--bs-toast-zindex: 1090;
|
||||||
|
@ -4433,7 +4436,7 @@ textarea.form-control-lg {
|
||||||
--bs-modal-width: 500px;
|
--bs-modal-width: 500px;
|
||||||
--bs-modal-padding: 1rem;
|
--bs-modal-padding: 1rem;
|
||||||
--bs-modal-margin: 0.5rem;
|
--bs-modal-margin: 0.5rem;
|
||||||
--bs-modal-color: ;
|
--bs-modal-color: var(--bs-body-color);
|
||||||
--bs-modal-bg: var(--bs-body-bg);
|
--bs-modal-bg: var(--bs-body-bg);
|
||||||
--bs-modal-border-color: var(--bs-border-color-translucent);
|
--bs-modal-border-color: var(--bs-border-color-translucent);
|
||||||
--bs-modal-border-width: var(--bs-border-width);
|
--bs-modal-border-width: var(--bs-border-width);
|
||||||
|
@ -4467,8 +4470,8 @@ textarea.form-control-lg {
|
||||||
margin: var(--bs-modal-margin);
|
margin: var(--bs-modal-margin);
|
||||||
pointer-events: none; }
|
pointer-events: none; }
|
||||||
.modal.fade .modal-dialog {
|
.modal.fade .modal-dialog {
|
||||||
transition: transform 0.3s ease-out;
|
transform: translate(0, -50px);
|
||||||
transform: translate(0, -50px); }
|
transition: transform 0.3s ease-out; }
|
||||||
@media (prefers-reduced-motion: reduce) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
.modal.fade .modal-dialog {
|
.modal.fade .modal-dialog {
|
||||||
transition: none; } }
|
transition: none; } }
|
||||||
|
@ -4529,7 +4532,10 @@ textarea.form-control-lg {
|
||||||
border-top-right-radius: var(--bs-modal-inner-border-radius); }
|
border-top-right-radius: var(--bs-modal-inner-border-radius); }
|
||||||
.modal-header .btn-close {
|
.modal-header .btn-close {
|
||||||
padding: calc(var(--bs-modal-header-padding-y) * .5) calc(var(--bs-modal-header-padding-x) * .5);
|
padding: calc(var(--bs-modal-header-padding-y) * .5) calc(var(--bs-modal-header-padding-x) * .5);
|
||||||
margin: calc(-.5 * var(--bs-modal-header-padding-y)) calc(-.5 * var(--bs-modal-header-padding-x)) calc(-.5 * var(--bs-modal-header-padding-y)) auto; }
|
margin-top: calc(-.5 * var(--bs-modal-header-padding-y));
|
||||||
|
margin-right: calc(-.5 * var(--bs-modal-header-padding-x));
|
||||||
|
margin-bottom: calc(-.5 * var(--bs-modal-header-padding-y));
|
||||||
|
margin-left: auto; }
|
||||||
|
|
||||||
.modal-title {
|
.modal-title {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
@ -4965,6 +4971,7 @@ textarea.form-control-lg {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background: none;
|
background: none;
|
||||||
|
filter: var(--bs-carousel-control-icon-filter);
|
||||||
border: 0;
|
border: 0;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
transition: opacity 0.15s ease; }
|
transition: opacity 0.15s ease; }
|
||||||
|
@ -4996,10 +5003,10 @@ textarea.form-control-lg {
|
||||||
background-size: 100% 100%; }
|
background-size: 100% 100%; }
|
||||||
|
|
||||||
.carousel-control-prev-icon {
|
.carousel-control-prev-icon {
|
||||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e") /*rtl:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")*/; }
|
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0'/%3e%3c/svg%3e") /*rtl:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708'/%3e%3c/svg%3e")*/; }
|
||||||
|
|
||||||
.carousel-control-next-icon {
|
.carousel-control-next-icon {
|
||||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e") /*rtl:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")*/; }
|
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708'/%3e%3c/svg%3e") /*rtl:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0'/%3e%3c/svg%3e")*/; }
|
||||||
|
|
||||||
.carousel-indicators {
|
.carousel-indicators {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -5023,7 +5030,7 @@ textarea.form-control-lg {
|
||||||
margin-left: 3px;
|
margin-left: 3px;
|
||||||
text-indent: -999px;
|
text-indent: -999px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background-color: #fff;
|
background-color: var(--bs-carousel-indicator-active-bg);
|
||||||
background-clip: padding-box;
|
background-clip: padding-box;
|
||||||
border: 0;
|
border: 0;
|
||||||
border-top: 10px solid transparent;
|
border-top: 10px solid transparent;
|
||||||
|
@ -5043,29 +5050,24 @@ textarea.form-control-lg {
|
||||||
left: 15%;
|
left: 15%;
|
||||||
padding-top: 1.25rem;
|
padding-top: 1.25rem;
|
||||||
padding-bottom: 1.25rem;
|
padding-bottom: 1.25rem;
|
||||||
color: #fff;
|
color: var(--bs-carousel-caption-color);
|
||||||
text-align: center; }
|
text-align: center; }
|
||||||
|
|
||||||
.carousel-dark .carousel-control-prev-icon,
|
.carousel-dark {
|
||||||
.carousel-dark .carousel-control-next-icon {
|
--bs-carousel-indicator-active-bg: #000;
|
||||||
filter: invert(1) grayscale(100); }
|
--bs-carousel-caption-color: #000;
|
||||||
|
--bs-carousel-control-icon-filter: invert(1) grayscale(100); }
|
||||||
|
|
||||||
.carousel-dark .carousel-indicators [data-bs-target] {
|
:root,
|
||||||
background-color: #000; }
|
[data-bs-theme="light"] {
|
||||||
|
--bs-carousel-indicator-active-bg: #fff;
|
||||||
|
--bs-carousel-caption-color: #fff;
|
||||||
|
--bs-carousel-control-icon-filter: ; }
|
||||||
|
|
||||||
.carousel-dark .carousel-caption {
|
[data-bs-theme="dark"] {
|
||||||
color: #000; }
|
--bs-carousel-indicator-active-bg: #000;
|
||||||
|
--bs-carousel-caption-color: #000;
|
||||||
[data-bs-theme="dark"] .carousel .carousel-control-prev-icon,
|
--bs-carousel-control-icon-filter: invert(1) grayscale(100); }
|
||||||
[data-bs-theme="dark"] .carousel .carousel-control-next-icon, .carousel[data-bs-theme="dark"] .carousel-control-prev-icon,
|
|
||||||
.carousel[data-bs-theme="dark"] .carousel-control-next-icon {
|
|
||||||
filter: invert(1) grayscale(100); }
|
|
||||||
|
|
||||||
[data-bs-theme="dark"] .carousel .carousel-indicators [data-bs-target], .carousel[data-bs-theme="dark"] .carousel-indicators [data-bs-target] {
|
|
||||||
background-color: #000; }
|
|
||||||
|
|
||||||
[data-bs-theme="dark"] .carousel .carousel-caption, .carousel[data-bs-theme="dark"] .carousel-caption {
|
|
||||||
color: #000; }
|
|
||||||
|
|
||||||
.spinner-grow,
|
.spinner-grow,
|
||||||
.spinner-border {
|
.spinner-border {
|
||||||
|
@ -5521,7 +5523,10 @@ textarea.form-control-lg {
|
||||||
padding: var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x); }
|
padding: var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x); }
|
||||||
.offcanvas-header .btn-close {
|
.offcanvas-header .btn-close {
|
||||||
padding: calc(var(--bs-offcanvas-padding-y) * .5) calc(var(--bs-offcanvas-padding-x) * .5);
|
padding: calc(var(--bs-offcanvas-padding-y) * .5) calc(var(--bs-offcanvas-padding-x) * .5);
|
||||||
margin: calc(-.5 * var(--bs-offcanvas-padding-y)) calc(-.5 * var(--bs-offcanvas-padding-x)) calc(-.5 * var(--bs-offcanvas-padding-y)) auto; }
|
margin-top: calc(-.5 * var(--bs-offcanvas-padding-y));
|
||||||
|
margin-right: calc(-.5 * var(--bs-offcanvas-padding-x));
|
||||||
|
margin-bottom: calc(-.5 * var(--bs-offcanvas-padding-y));
|
||||||
|
margin-left: auto; }
|
||||||
|
|
||||||
.offcanvas-title {
|
.offcanvas-title {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
@ -5816,6 +5821,9 @@ textarea.form-control-lg {
|
||||||
.visually-hidden:not(caption),
|
.visually-hidden:not(caption),
|
||||||
.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption) {
|
.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption) {
|
||||||
position: absolute !important; }
|
position: absolute !important; }
|
||||||
|
.visually-hidden *,
|
||||||
|
.visually-hidden-focusable:not(:focus):not(:focus-within) * {
|
||||||
|
overflow: hidden !important; }
|
||||||
|
|
||||||
.stretched-link::after {
|
.stretched-link::after {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -9316,7 +9324,7 @@ h1, .h1 {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto; }
|
margin-right: auto; }
|
||||||
|
|
||||||
.splash[ng-cloak] {
|
[ng-cloak].splash {
|
||||||
display: block !important; }
|
display: block !important; }
|
||||||
|
|
||||||
[ng-cloak] {
|
[ng-cloak] {
|
||||||
|
@ -9456,7 +9464,7 @@ strong {
|
||||||
-webkit-transition: opacity 0.12s ease-in-out;
|
-webkit-transition: opacity 0.12s ease-in-out;
|
||||||
-o-transition: opacity 0.12s ease-in-out; }
|
-o-transition: opacity 0.12s ease-in-out; }
|
||||||
|
|
||||||
.navbar a.navbar-brand:hover span {
|
.navbar a:hover.navbar-brand span {
|
||||||
opacity: 1; }
|
opacity: 1; }
|
||||||
|
|
||||||
.navbar li > a, .navbar-text {
|
.navbar li > a, .navbar-text {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<img src="../static/resources/images/pets.png" th:src="@{/resources/images/pets.png}" />
|
<img src="../static/resources/images/pets.png" th:src="@{/resources/images/pets.png}" />
|
||||||
<h2>Something happened...</h2>
|
<h2 th:text="#{somethingHappened}">Something happened...</h2>
|
||||||
<p th:text="${message}">Exception message</p>
|
<p th:text="${message}">Exception message</p>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
|
@ -1,28 +1,27 @@
|
||||||
<html>
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html xmlns:th="https://www.thymeleaf.org">
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<form>
|
<form>
|
||||||
<th:block th:fragment="input (label, name, type)">
|
<th:block th:fragment="input (label, name, type)">
|
||||||
<div th:with="valid=${!#fields.hasErrors(name)}"
|
<div th:with="valid=${!#fields.hasErrors(name)}" th:class="${'form-group' + (valid ? '' : ' has-error')}"
|
||||||
th:class="${'form-group' + (valid ? '' : ' has-error')}"
|
|
||||||
class="form-group">
|
class="form-group">
|
||||||
<label class="col-sm-2 control-label" th:text="${label}">Label</label>
|
<label th:for="${name}" class="col-sm-2 control-label" th:text="${label}">Label</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<div th:switch="${type}">
|
<div th:switch="${type}">
|
||||||
<input th:case="'text'" class="form-control" type="text" th:field="*{__${name}__}" />
|
<input th:case="'text'" class="form-control" type="text" th:field="*{__${name}__}" />
|
||||||
<input th:case="'date'" class="form-control" type="date" th:field="*{__${name}__}" />
|
<input th:case="'date'" class="form-control" type="date" th:field="*{__${name}__}" />
|
||||||
</div>
|
</div>
|
||||||
<span th:if="${valid}"
|
<span th:if="${valid}" class="fa fa-ok form-control-feedback" aria-hidden="true"></span>
|
||||||
class="fa fa-ok form-control-feedback"
|
|
||||||
aria-hidden="true"></span>
|
|
||||||
<th:block th:if="${!valid}">
|
<th:block th:if="${!valid}">
|
||||||
<span
|
<span class="fa fa-remove form-control-feedback" aria-hidden="true"></span>
|
||||||
class="fa fa-remove form-control-feedback"
|
<span class="help-inline" th:errors="*{__${name}__}" th:text="#{error}">Error</span>
|
||||||
aria-hidden="true"></span>
|
|
||||||
<span class="help-inline" th:errors="*{__${name}__}">Error</span>
|
|
||||||
</th:block>
|
</th:block>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</th:block>
|
</th:block>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -1,5 +1,6 @@
|
||||||
<!doctype html>
|
<!DOCTYPE html>
|
||||||
<html th:fragment="layout (template, menu)">
|
|
||||||
|
<html th:fragment="layout (template, menu)" xmlns:th="https://www.thymeleaf.org">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
|
|
||||||
|
@ -7,16 +8,8 @@
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
<link rel="shortcut icon" type="image/x-icon" th:href="@{/resources/images/favicon.png}">
|
<link rel="shortcut icon" type="image/x-icon" th:href="@{/resources/images/favicon.png}">
|
||||||
|
<title th:text="#{layoutTitle}">PetClinic :: a Spring Framework demonstration</title>
|
||||||
<title>PetClinic :: a Spring Framework demonstration</title>
|
|
||||||
|
|
||||||
<!--[if lt IE 9]>
|
|
||||||
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
|
||||||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
|
||||||
<![endif]-->
|
|
||||||
|
|
||||||
<link th:href="@{/webjars/font-awesome/css/font-awesome.min.css}" rel="stylesheet">
|
<link th:href="@{/webjars/font-awesome/css/font-awesome.min.css}" rel="stylesheet">
|
||||||
<link rel="stylesheet" th:href="@{/resources/css/petclinic.css}" />
|
<link rel="stylesheet" th:href="@{/resources/css/petclinic.css}" />
|
||||||
|
|
||||||
|
@ -45,25 +38,25 @@
|
||||||
|
|
||||||
<ul class="nav navbar-nav me-auto">
|
<ul class="nav navbar-nav me-auto">
|
||||||
|
|
||||||
<li th:replace="~{::menuItem ('/','home','home page','home','Home')}">
|
<li th:replace="~{::menuItem ('/','home','home page','home',#{home})}">
|
||||||
<span class="fa fa-home" aria-hidden="true"></span>
|
<span class="fa fa-home" aria-hidden="true"></span>
|
||||||
<span>Home</span>
|
<span th:text="#{home}">Home</span>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li th:replace="~{::menuItem ('/owners/find','owners','find owners','search','Find owners')}">
|
<li th:replace="~{::menuItem ('/owners/find','owners','find owners','search',#{findOwners})}">
|
||||||
<span class="fa fa-search" aria-hidden="true"></span>
|
<span class="fa fa-search" aria-hidden="true"></span>
|
||||||
<span>Find owners</span>
|
<span th:text="#{findOwners}">Find owners</span>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li th:replace="~{::menuItem ('/vets.html','vets','veterinarians','th-list','Veterinarians')}">
|
<li th:replace="~{::menuItem ('/vets.html','vets','veterinarians','th-list',#{vets})}">
|
||||||
<span class="fa fa-th-list" aria-hidden="true"></span>
|
<span class="fa fa-th-list" aria-hidden="true"></span>
|
||||||
<span>Veterinarians</span>
|
<span th:text="#{vets}">Veterinarians</span>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li
|
<li
|
||||||
th:replace="~{::menuItem ('/oups','error','trigger a RuntimeException to see how it is handled','exclamation-triangle','Error')}">
|
th:replace="~{::menuItem ('/oups','error','trigger a RuntimeException to see how it is handled','exclamation-triangle',#{error})}">
|
||||||
<span class="fa exclamation-triangle" aria-hidden="true"></span>
|
<span class="fa exclamation-triangle" aria-hidden="true"></span>
|
||||||
<span>Error</span>
|
<span th:text="#{error}">Error</span>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -80,7 +73,8 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 text-center">
|
<div class="col-12 text-center">
|
||||||
<img src="../static/images/spring-logo.svg" th:src="@{/resources/images/spring-logo.svg}" alt="VMware Tanzu Logo" class="logo">
|
<img src="../static/images/spring-logo.svg" th:src="@{/resources/images/spring-logo.svg}"
|
||||||
|
alt="VMware Tanzu Logo" class="logo">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,29 +1,27 @@
|
||||||
<html>
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html xmlns:th="https://www.thymeleaf.org">
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<form>
|
<form>
|
||||||
<th:block th:fragment="select (label, name, items)">
|
<th:block th:fragment="select (label, name, items)">
|
||||||
<div th:with="valid=${!#fields.hasErrors(name)}"
|
<div th:with="valid=${!#fields.hasErrors(name)}" th:class="${'form-group' + (valid ? '' : ' has-error')}"
|
||||||
th:class="${'form-group' + (valid ? '' : ' has-error')}"
|
|
||||||
class="form-group">
|
class="form-group">
|
||||||
<label class="col-sm-2 control-label" th:text="${label}">Label</label>
|
<label th:for="${name}" class="col-sm-2 control-label" th:text="${label}">Label</label>
|
||||||
|
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<select th:field="*{__${name}__}">
|
<select th:field="*{__${name}__}">
|
||||||
<option th:each="item : ${items}" th:value="${item}"
|
<option th:each="item : ${items}" th:value="${item}" th:text="${item}">dog</option>
|
||||||
th:text="${item}">dog</option>
|
|
||||||
</select>
|
</select>
|
||||||
<span th:if="${valid}"
|
<span th:if="${valid}" class="fa fa-ok form-control-feedback" aria-hidden="true"></span>
|
||||||
class="fa fa-ok form-control-feedback"
|
|
||||||
aria-hidden="true"></span>
|
|
||||||
<th:block th:if="${!valid}">
|
<th:block th:if="${!valid}">
|
||||||
<span
|
<span class="fa fa-remove form-control-feedback" aria-hidden="true"></span>
|
||||||
class="fa fa-remove form-control-feedback"
|
<span class="help-inline" th:errors="*{__${name}__}" th:text="#{error}">Error</span>
|
||||||
aria-hidden="true"></span>
|
|
||||||
<span class="help-inline" th:errors="*{__${name}__}">Error</span>
|
|
||||||
</th:block>
|
</th:block>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</th:block>
|
</th:block>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -1,30 +1,25 @@
|
||||||
<html xmlns:th="https://www.thymeleaf.org"
|
<!DOCTYPE html>
|
||||||
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
|
||||||
|
<html xmlns:th="https://www.thymeleaf.org" th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<h2>Owner</h2>
|
<h2 th:text="#{owner}">Owner</h2>
|
||||||
<form th:object="${owner}" class="form-horizontal" id="add-owner-form" method="post">
|
<form th:object="${owner}" class="form-horizontal" id="add-owner-form" method="post">
|
||||||
<div class="form-group has-feedback">
|
<div class="form-group has-feedback">
|
||||||
<input
|
<input th:replace="~{fragments/inputField :: input (#{firstName}, 'firstName', 'text')}" />
|
||||||
th:replace="~{fragments/inputField :: input ('First Name', 'firstName', 'text')}" />
|
<input th:replace="~{fragments/inputField :: input (#{lastName}, 'lastName', 'text')}" />
|
||||||
<input
|
<input th:replace="~{fragments/inputField :: input (#{address}, 'address', 'text')}" />
|
||||||
th:replace="~{fragments/inputField :: input ('Last Name', 'lastName', 'text')}" />
|
<input th:replace="~{fragments/inputField :: input (#{city}, 'city', 'text')}" />
|
||||||
<input
|
<input th:replace="~{fragments/inputField :: input (#{telephone}, 'telephone', 'text')}" />
|
||||||
th:replace="~{fragments/inputField :: input ('Address', 'address', 'text')}" />
|
|
||||||
<input
|
|
||||||
th:replace="~{fragments/inputField :: input ('City', 'city', 'text')}" />
|
|
||||||
<input
|
|
||||||
th:replace="~{fragments/inputField :: input ('Telephone', 'telephone', 'text')}" />
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-offset-2 col-sm-10">
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
<button
|
<button th:with="text=${owner['new']} ? #{addOwner} : #{updateOwner}" class="btn btn-primary" type="submit"
|
||||||
th:with="text=${owner['new']} ? 'Add Owner' : 'Update Owner'"
|
th:text="${text}">Add Owner</button>
|
||||||
class="btn btn-primary" type="submit" th:text="${text}">Add
|
|
||||||
Owner</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -1,34 +1,35 @@
|
||||||
<html xmlns:th="https://www.thymeleaf.org"
|
<!DOCTYPE html>
|
||||||
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
|
||||||
|
<html xmlns:th="https://www.thymeleaf.org" th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<h2>Find Owners</h2>
|
<h2 th:text="#{findOwners}">Find Owners</h2>
|
||||||
|
|
||||||
<form th:object="${owner}" th:action="@{/owners}" method="get"
|
<form th:object="${owner}" th:action="@{/owners}" method="get" class="form-horizontal" id="search-owner-form">
|
||||||
class="form-horizontal" id="search-owner-form">
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="control-group" id="lastNameGroup">
|
<div class="control-group" id="lastNameGroup">
|
||||||
<label class="col-sm-2 control-label">Last name </label>
|
<label class="col-sm-2 control-label" th:text="#{lastName}">Last name </label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<input class="form-control" th:field="*{lastName}" size="30"
|
<input class="form-control" th:field="*{lastName}" size="30" maxlength="80" />
|
||||||
maxlength="80" /> <span class="help-inline"><div
|
<span class="help-inline">
|
||||||
th:if="${#fields.hasAnyErrors()}">
|
<div th:if="${#fields.hasAnyErrors()}">
|
||||||
<p th:each="err : ${#fields.allErrors()}" th:text="${err}">Error</p>
|
<p th:each="err : ${#fields.allErrors()}" th:text="${err}">Error</p>
|
||||||
</div></span>
|
</div>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-offset-2 col-sm-10">
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
<button type="submit" class="btn btn-primary">Find
|
<button type="submit" class="btn btn-primary" th:text="#{findOwner}">Find Owner</button>
|
||||||
Owner</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a class="btn btn-primary" th:href="@{/owners/new}">Add Owner</a>
|
<a class="btn btn-primary" th:href="@{/owners/new}" th:text="#{addOwner}">Add Owner</a>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -1,12 +1,10 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
||||||
<html xmlns:th="https://www.thymeleaf.org"
|
<html xmlns:th="https://www.thymeleaf.org" th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
||||||
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
<h2 th:text="#{ownerInformation}">Owner Information</h2>
|
||||||
<h2>Owner Information</h2>
|
|
||||||
|
|
||||||
<div th:if="${message}" class="alert alert-success" id="success-message">
|
<div th:if="${message}" class="alert alert-success" id="success-message">
|
||||||
<span th:text="${message}"></span>
|
<span th:text="${message}"></span>
|
||||||
|
@ -16,49 +14,45 @@
|
||||||
<span th:text="${error}"></span>
|
<span th:text="${error}"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<table class="table table-striped" th:object="${owner}">
|
<table class="table table-striped" th:object="${owner}">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th th:text="#{name}">Name</th>
|
||||||
<td><b th:text="*{firstName + ' ' + lastName}"></b></td>
|
<td><b th:text="*{firstName + ' ' + lastName}"></b></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Address</th>
|
<th th:text="#{address}">Address</th>
|
||||||
<td th:text="*{address}"></td>
|
<td th:text="*{address}"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>City</th>
|
<th th:text="#{city}">City</th>
|
||||||
<td th:text="*{city}"></td>
|
<td th:text="*{city}"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Telephone</th>
|
<th th:text="#{telephone}">Telephone</th>
|
||||||
<td th:text="*{telephone}"></td>
|
<td th:text="*{telephone}"></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<a th:href="@{__${owner.id}__/edit}" class="btn btn-primary">Edit
|
<a th:href="@{__${owner.id}__/edit}" class="btn btn-primary" th:text="#{editOwner}">Edit
|
||||||
Owner</a>
|
Owner</a>
|
||||||
<a th:href="@{__${owner.id}__/pets/new}" class="btn btn-primary">Add
|
<a th:href="@{__${owner.id}__/pets/new}" class="btn btn-primary" th:text="#{addNewPet}">Add
|
||||||
New Pet</a>
|
New Pet</a>
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<h2>Pets and Visits</h2>
|
<h2 th:text="#{petsAndVisits}">Pets and Visits</h2>
|
||||||
|
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
|
|
||||||
<tr th:each="pet : ${owner.pets}">
|
<tr th:each="pet : ${owner.pets}">
|
||||||
<td valign="top">
|
<td valign="top">
|
||||||
<dl class="dl-horizontal">
|
<dl class="dl-horizontal">
|
||||||
<dt>Name</dt>
|
<dt th:text="#{name}">Name</dt>
|
||||||
<dd th:text="${pet.name}"></dd>
|
<dd th:text="${pet.name}"></dd>
|
||||||
<dt>Birth Date</dt>
|
<dt th:text="#{birthDate}">Birth Date</dt>
|
||||||
<dd
|
<dd th:text="${#temporals.format(pet.birthDate, 'yyyy-MM-dd')}"></dd>
|
||||||
th:text="${#temporals.format(pet.birthDate, 'yyyy-MM-dd')}"></dd>
|
<dt th:text="#{type}">Type</dt>
|
||||||
<dt>Type</dt>
|
|
||||||
<dd th:text="${pet.type}"></dd>
|
<dd th:text="${pet.type}"></dd>
|
||||||
</dl>
|
</dl>
|
||||||
</td>
|
</td>
|
||||||
|
@ -66,8 +60,8 @@
|
||||||
<table class="table-condensed">
|
<table class="table-condensed">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Visit Date</th>
|
<th th:text="#{visitDate}">Visit Date</th>
|
||||||
<th>Description</th>
|
<th th:text="#{description}">Description</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr th:each="visit : ${pet.visits}">
|
<tr th:each="visit : ${pet.visits}">
|
||||||
|
@ -75,8 +69,8 @@
|
||||||
<td th:text="${visit?.description}"></td>
|
<td th:text="${visit?.description}"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><a th:href="@{__${owner.id}__/pets/__${pet.id}__/edit}">Edit Pet</a></td>
|
<td><a th:href="@{__${owner.id}__/pets/__${pet.id}__/edit}" th:text="#{editPet}">Edit Pet</a></td>
|
||||||
<td><a th:href="@{__${owner.id}__/pets/__${pet.id}__/visits/new}">Add Visit</a></td>
|
<td><a th:href="@{__${owner.id}__/pets/__${pet.id}__/visits/new}" th:text="#{addVisit}">Add Visit</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -4,16 +4,16 @@
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<h2>Owners</h2>
|
<h2 th:text="#{owners}">Owners</h2>
|
||||||
|
|
||||||
<table id="owners" class="table table-striped">
|
<table id="owners" class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width: 150px;">Name</th>
|
<th th:text="#{name}" style="width: 150px;">Name</th>
|
||||||
<th style="width: 200px;">Address</th>
|
<th th:text="#{address}" style="width: 200px;">Address</th>
|
||||||
<th>City</th>
|
<th th:text="#{city}">City</th>
|
||||||
<th style="width: 120px">Telephone</th>
|
<th th:text="#{telephone}" style="width: 120px">Telephone</th>
|
||||||
<th>Pets</th>
|
<th th:text="#{pets}">Pets</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div th:if="${totalPages > 1}">
|
<div th:if="${totalPages > 1}">
|
||||||
<span>Pages:</span>
|
<span th:text="#{pages}">Pages:</span>
|
||||||
<span>[</span>
|
<span>[</span>
|
||||||
<span th:each="i: ${#numbers.sequence(1, totalPages)}">
|
<span th:each="i: ${#numbers.sequence(1, totalPages)}">
|
||||||
<a th:if="${currentPage != i}" th:href="@{'/owners?page=' + ${i}}">[[${i}]]</a>
|
<a th:if="${currentPage != i}" th:href="@{'/owners?page=' + ${i}}">[[${i}]]</a>
|
||||||
|
@ -37,26 +37,25 @@
|
||||||
</span>
|
</span>
|
||||||
<span>] </span>
|
<span>] </span>
|
||||||
<span>
|
<span>
|
||||||
<a th:if="${currentPage > 1}" th:href="@{'/owners?page=1'}" title="First"
|
<a th:if="${currentPage > 1}" th:href="@{'/owners?page=1'}" th:title="#{first}" class="fa fa-fast-backward"></a>
|
||||||
class="fa fa-fast-backward"></a>
|
<span th:unless="${currentPage > 1}" th:title="#{first}" class="fa fa-fast-backward"></span>
|
||||||
<span th:unless="${currentPage > 1}" title="First" class="fa fa-fast-backward"></span>
|
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<a th:if="${currentPage > 1}" th:href="@{'/owners?page=__${currentPage - 1}__'}" title="Previous"
|
<a th:if="${currentPage > 1}" th:href="@{'/owners?page=__${currentPage - 1}__'}" th:title="#{previous}"
|
||||||
class="fa fa-step-backward"></a>
|
class="fa fa-step-backward"></a>
|
||||||
<span th:unless="${currentPage > 1}" title="Previous" class="fa fa-step-backward"></span>
|
<span th:unless="${currentPage > 1}" th:title="#{previous}" class="fa fa-step-backward"></span>
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<a th:if="${currentPage < totalPages}" th:href="@{'/owners?page=__${currentPage + 1}__'}" title="Next"
|
<a th:if="${currentPage < totalPages}" th:href="@{'/owners?page=__${currentPage + 1}__'}" th:title="#{next}"
|
||||||
class="fa fa-step-forward"></a>
|
class="fa fa-step-forward"></a>
|
||||||
<span th:unless="${currentPage < totalPages}" title="Next" class="fa fa-step-forward"></span>
|
<span th:unless="${currentPage < totalPages}" th:title="#{next}" class="fa fa-step-forward"></span>
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<a th:if="${currentPage < totalPages}" th:href="@{'/owners?page=__${totalPages}__'}" title="Last"
|
<a th:if="${currentPage < totalPages}" th:href="@{'/owners?page=__${totalPages}__'}" th:title="#{last}"
|
||||||
class="fa fa-fast-forward"></a>
|
class="fa fa-fast-forward"></a>
|
||||||
<span th:unless="${currentPage < totalPages}" title="Last" class="fa fa-step-forward"></span>
|
<span th:unless="${currentPage < totalPages}" th:title="#{last}" class="fa fa-fast-forward"></span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
|
||||||
|
|
||||||
|
</html>
|
|
@ -1,34 +1,30 @@
|
||||||
<html xmlns:th="https://www.thymeleaf.org"
|
<!DOCTYPE html>
|
||||||
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
|
||||||
|
<html xmlns:th="https://www.thymeleaf.org" th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<h2>
|
<h2>
|
||||||
<th:block th:if="${pet['new']}">New </th:block>
|
<th:block th:if="${pet['new']}" th:text="#{new}">New </th:block>
|
||||||
Pet
|
<span th:text="#{pet}">Pet</span>
|
||||||
</h2>
|
</h2>
|
||||||
<form th:object="${pet}" class="form-horizontal" method="post">
|
<form th:object="${pet}" class="form-horizontal" method="post">
|
||||||
<input type="hidden" name="id" th:value="*{id}" />
|
<input type="hidden" name="id" th:value="*{id}" />
|
||||||
<div class="form-group has-feedback">
|
<div class="form-group has-feedback">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-sm-2 control-label">Owner</label>
|
<label class="col-sm-2 control-label" th:text="#{owner}">Owner</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<span th:text="${owner?.firstName + ' ' + owner?.lastName}" />
|
<span th:text="${owner?.firstName + ' ' + owner?.lastName}" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input th:replace="~{fragments/inputField :: input ('Name', 'name', 'text')}" />
|
||||||
th:replace="~{fragments/inputField :: input ('Name', 'name', 'text')}" />
|
<input th:replace="~{fragments/inputField :: input ('Birth Date', 'birthDate', 'date')}" />
|
||||||
<input
|
<input th:replace="~{fragments/selectField :: select ('Type', 'type', ${types})}" />
|
||||||
th:replace="~{fragments/inputField :: input ('Birth Date', 'birthDate', 'date')}" />
|
|
||||||
<input
|
|
||||||
th:replace="~{fragments/selectField :: select ('Type', 'type', ${types})}" />
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-offset-2 col-sm-10">
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
<button
|
<button th:with="text=${pet['new']} ? 'Add Pet' : 'Update Pet'" class="btn btn-primary" type="submit"
|
||||||
th:with="text=${pet['new']} ? 'Add Pet' : 'Update Pet'"
|
th:text="${text}">Add Pet</button>
|
||||||
class="btn btn-primary" type="submit" th:text="${text}">Add
|
|
||||||
Pet</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -1,55 +1,52 @@
|
||||||
<html xmlns:th="https://www.thymeleaf.org"
|
<!DOCTYPE html>
|
||||||
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
|
||||||
|
<html xmlns:th="https://www.thymeleaf.org" th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<h2>
|
<h2>
|
||||||
<th:block th:if="${visit['new']}">New </th:block>
|
<th:block th:if="${visit['new']}" th:text="#{new}">New </th:block>
|
||||||
Visit
|
Visit
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<b>Pet</b>
|
<b th:text="#{pet}">Pet</b>
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th th:text="#{name}">Name</th>
|
||||||
<th>Birth Date</th>
|
<th th:text="#{birthDate}">Birth Date</th>
|
||||||
<th>Type</th>
|
<th th:text="#{type}">Type</th>
|
||||||
<th>Owner</th>
|
<th th:text="#{owner}">Owner</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td th:text="${pet.name}"></td>
|
<td th:text="${pet.name}"></td>
|
||||||
<td
|
<td th:text="${#temporals.format(pet.birthDate, 'yyyy-MM-dd')}"></td>
|
||||||
th:text="${#temporals.format(pet.birthDate, 'yyyy-MM-dd')}"></td>
|
|
||||||
<td th:text="${pet.type}"></td>
|
<td th:text="${pet.type}"></td>
|
||||||
<td
|
<td th:text="${owner?.firstName + ' ' + owner?.lastName}"></td>
|
||||||
th:text="${owner?.firstName + ' ' + owner?.lastName}"></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<form th:object="${visit}" class="form-horizontal" method="post">
|
<form th:object="${visit}" class="form-horizontal" method="post">
|
||||||
<div class="form-group has-feedback">
|
<div class="form-group has-feedback">
|
||||||
<input
|
<input th:replace="~{fragments/inputField :: input ('Date', 'date', 'date')}" />
|
||||||
th:replace="~{fragments/inputField :: input ('Date', 'date', 'date')}" />
|
<input th:replace="~{fragments/inputField :: input ('Description', 'description', 'text')}" />
|
||||||
<input
|
|
||||||
th:replace="~{fragments/inputField :: input ('Description', 'description', 'text')}" />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-offset-2 col-sm-10">
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
<input type="hidden" name="petId" th:value="${pet.id}" />
|
<input type="hidden" name="petId" th:value="${pet.id}" />
|
||||||
<button class="btn btn-primary" type="submit">Add Visit</button>
|
<button class="btn btn-primary" type="submit" th:text="#{addVisit}">Add Visit</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
<b>Previous Visits</b>
|
<b th:text="#{previousVisits}">Previous Visits</b>
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Date</th>
|
<th th:text="#{date}">Date</th>
|
||||||
<th>Description</th>
|
<th th:text="#{description}">Description</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr th:if="${!visit['new']}" th:each="visit : ${pet.visits}">
|
<tr th:if="${!visit['new']}" th:each="visit : ${pet.visits}">
|
||||||
<td th:text="${#temporals.format(visit.date, 'yyyy-MM-dd')}"></td>
|
<td th:text="${#temporals.format(visit.date, 'yyyy-MM-dd')}"></td>
|
||||||
|
@ -58,4 +55,5 @@
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -1,31 +1,30 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
||||||
<html xmlns:th="https://www.thymeleaf.org"
|
<html xmlns:th="https://www.thymeleaf.org" th:replace="~{fragments/layout :: layout (~{::body},'vets')}">
|
||||||
th:replace="~{fragments/layout :: layout (~{::body},'vets')}">
|
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<h2>Veterinarians</h2>
|
<h2 th:text="#{vets}">Veterinarians</h2>
|
||||||
|
|
||||||
<table id="vets" class="table table-striped">
|
<table id="vets" class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th th:text="#{name}">Name</th>
|
||||||
<th>Specialties</th>
|
<th th:text="#{specialties}">Specialties</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr th:each="vet : ${listVets}">
|
<tr th:each="vet : ${listVets}">
|
||||||
<td th:text="${vet.firstName + ' ' + vet.lastName}"></td>
|
<td th:text="${vet.firstName + ' ' + vet.lastName}"></td>
|
||||||
<td><span th:each="specialty : ${vet.specialties}"
|
<td>
|
||||||
th:text="${specialty.name + ' '}"/> <span
|
<span th:each="specialty : ${vet.specialties}" th:text="${specialty.name + ' '}" /> <span
|
||||||
th:if="${vet.nrOfSpecialties == 0}">none</span></td>
|
th:if="${vet.nrOfSpecialties == 0}" th:text="#{none}">none</span>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div th:if="${totalPages > 1}">
|
<div th:if="${totalPages > 1}">
|
||||||
<span>Pages:</span>
|
<span th:text="#{pages}">Pages:</span>
|
||||||
<span>[</span>
|
<span>[</span>
|
||||||
<span th:each="i: ${#numbers.sequence(1, totalPages)}">
|
<span th:each="i: ${#numbers.sequence(1, totalPages)}">
|
||||||
<a th:if="${currentPage != i}" th:href="@{'/vets.html?page=__${i}__'}">[[${i}]]</a>
|
<a th:if="${currentPage != i}" th:href="@{'/vets.html?page=__${i}__'}">[[${i}]]</a>
|
||||||
|
@ -33,25 +32,26 @@
|
||||||
</span>
|
</span>
|
||||||
<span>] </span>
|
<span>] </span>
|
||||||
<span>
|
<span>
|
||||||
<a th:if="${currentPage > 1}" th:href="@{'/vets.html?page=1'}" title="First"
|
<a th:if="${currentPage > 1}" th:href="@{'/vets.html?page=1'}" th:title="#{first}"
|
||||||
class="fa fa-fast-backward"></a>
|
class="fa fa-fast-backward"></a>
|
||||||
<span th:unless="${currentPage > 1}" title="First" class="fa fa-fast-backward"></span>
|
<span th:unless="${currentPage > 1}" th:title="#{first}" class="fa fa-fast-backward"></span>
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<a th:if="${currentPage > 1}" th:href="@{'/vets.html?page=__${currentPage - 1}__'}" title="Previous"
|
<a th:if="${currentPage > 1}" th:href="@{'/vets.html?page=__${currentPage - 1}__'}" th:title="#{previous}"
|
||||||
class="fa fa-step-backward"></a>
|
class="fa fa-step-backward"></a>
|
||||||
<span th:unless="${currentPage > 1}" title="Previous" class="fa fa-step-backward"></span>
|
<span th:unless="${currentPage > 1}" th:title="#{previous}" class="fa fa-step-backward"></span>
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<a th:if="${currentPage < totalPages}" th:href="@{'/vets.html?page=__${currentPage + 1}__'}" title="Next"
|
<a th:if="${currentPage < totalPages}" th:href="@{'/vets.html?page=__${currentPage + 1}__'}" th:title="#{next}"
|
||||||
class="fa fa-step-forward"></a>
|
class="fa fa-step-forward"></a>
|
||||||
<span th:unless="${currentPage < totalPages}" title="Next" class="fa fa-step-forward"></span>
|
<span th:unless="${currentPage < totalPages}" th:title="#{next}" class="fa fa-step-forward"></span>
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<a th:if="${currentPage < totalPages}" th:href="@{'/vets.html?page=__${totalPages}__'}" title="Last"
|
<a th:if="${currentPage < totalPages}" th:href="@{'/vets.html?page=__${totalPages}__'}" th:title="#{last}"
|
||||||
class="fa fa-fast-forward"></a>
|
class="fa fa-fast-forward"></a>
|
||||||
<span th:unless="${currentPage < totalPages}" title="Last" class="fa fa-fast-forward"></span>
|
<span th:unless="${currentPage < totalPages}" th:title="#{last}" class="fa fa-fast-forward"></span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -36,6 +36,7 @@ import org.springframework.web.client.RestTemplate;
|
||||||
import org.testcontainers.containers.MySQLContainer;
|
import org.testcontainers.containers.MySQLContainer;
|
||||||
import org.testcontainers.junit.jupiter.Container;
|
import org.testcontainers.junit.jupiter.Container;
|
||||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
|
import org.testcontainers.utility.DockerImageName;
|
||||||
|
|
||||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||||
@ActiveProfiles("mysql")
|
@ActiveProfiles("mysql")
|
||||||
|
@ -46,7 +47,7 @@ class MySqlIntegrationTests {
|
||||||
|
|
||||||
@ServiceConnection
|
@ServiceConnection
|
||||||
@Container
|
@Container
|
||||||
static MySQLContainer<?> container = new MySQLContainer<>("mysql:9.1");
|
static MySQLContainer<?> container = new MySQLContainer<>(DockerImageName.parse("mysql:9.2"));
|
||||||
|
|
||||||
@LocalServerPort
|
@LocalServerPort
|
||||||
int port;
|
int port;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -22,12 +22,12 @@ import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Profile;
|
import org.springframework.context.annotation.Profile;
|
||||||
import org.testcontainers.containers.MySQLContainer;
|
import org.testcontainers.containers.MySQLContainer;
|
||||||
|
import org.testcontainers.utility.DockerImageName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PetClinic Spring Boot Application.
|
* PetClinic Spring Boot Application.
|
||||||
*
|
*
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
public class MysqlTestApplication {
|
public class MysqlTestApplication {
|
||||||
|
@ -36,7 +36,7 @@ public class MysqlTestApplication {
|
||||||
@Profile("mysql")
|
@Profile("mysql")
|
||||||
@Bean
|
@Bean
|
||||||
static MySQLContainer<?> container() {
|
static MySQLContainer<?> container() {
|
||||||
return new MySQLContainer<>("mysql:9.1");
|
return new MySQLContainer<>(DockerImageName.parse("mysql:9.2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.samples.petclinic.owner;
|
package org.springframework.samples.petclinic.owner;
|
||||||
|
|
||||||
import org.assertj.core.util.Lists;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.condition.DisabledInNativeImage;
|
import org.junit.jupiter.api.condition.DisabledInNativeImage;
|
||||||
|
@ -31,6 +30,7 @@ import org.springframework.test.web.servlet.MockMvc;
|
||||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.empty;
|
import static org.hamcrest.Matchers.empty;
|
||||||
|
@ -92,9 +92,7 @@ class OwnerControllerTests {
|
||||||
|
|
||||||
Owner george = george();
|
Owner george = george();
|
||||||
given(this.owners.findByLastNameStartingWith(eq("Franklin"), any(Pageable.class)))
|
given(this.owners.findByLastNameStartingWith(eq("Franklin"), any(Pageable.class)))
|
||||||
.willReturn(new PageImpl<>(Lists.newArrayList(george)));
|
.willReturn(new PageImpl<>(List.of(george)));
|
||||||
|
|
||||||
given(this.owners.findAll(any(Pageable.class))).willReturn(new PageImpl<>(Lists.newArrayList(george)));
|
|
||||||
|
|
||||||
given(this.owners.findById(TEST_OWNER_ID)).willReturn(Optional.of(george));
|
given(this.owners.findById(TEST_OWNER_ID)).willReturn(Optional.of(george));
|
||||||
Visit visit = new Visit();
|
Visit visit = new Visit();
|
||||||
|
@ -143,14 +141,14 @@ class OwnerControllerTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testProcessFindFormSuccess() throws Exception {
|
void testProcessFindFormSuccess() throws Exception {
|
||||||
Page<Owner> tasks = new PageImpl<>(Lists.newArrayList(george(), new Owner()));
|
Page<Owner> tasks = new PageImpl<>(List.of(george(), new Owner()));
|
||||||
when(this.owners.findByLastNameStartingWith(anyString(), any(Pageable.class))).thenReturn(tasks);
|
when(this.owners.findByLastNameStartingWith(anyString(), any(Pageable.class))).thenReturn(tasks);
|
||||||
mockMvc.perform(get("/owners?page=1")).andExpect(status().isOk()).andExpect(view().name("owners/ownersList"));
|
mockMvc.perform(get("/owners?page=1")).andExpect(status().isOk()).andExpect(view().name("owners/ownersList"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testProcessFindFormByLastName() throws Exception {
|
void testProcessFindFormByLastName() throws Exception {
|
||||||
Page<Owner> tasks = new PageImpl<>(Lists.newArrayList(george()));
|
Page<Owner> tasks = new PageImpl<>(List.of(george()));
|
||||||
when(this.owners.findByLastNameStartingWith(eq("Franklin"), any(Pageable.class))).thenReturn(tasks);
|
when(this.owners.findByLastNameStartingWith(eq("Franklin"), any(Pageable.class))).thenReturn(tasks);
|
||||||
mockMvc.perform(get("/owners?page=1").param("lastName", "Franklin"))
|
mockMvc.perform(get("/owners?page=1").param("lastName", "Franklin"))
|
||||||
.andExpect(status().is3xxRedirection())
|
.andExpect(status().is3xxRedirection())
|
||||||
|
@ -159,7 +157,7 @@ class OwnerControllerTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testProcessFindFormNoOwnersFound() throws Exception {
|
void testProcessFindFormNoOwnersFound() throws Exception {
|
||||||
Page<Owner> tasks = new PageImpl<>(Lists.newArrayList());
|
Page<Owner> tasks = new PageImpl<>(List.of());
|
||||||
when(this.owners.findByLastNameStartingWith(eq("Unknown Surname"), any(Pageable.class))).thenReturn(tasks);
|
when(this.owners.findByLastNameStartingWith(eq("Unknown Surname"), any(Pageable.class))).thenReturn(tasks);
|
||||||
mockMvc.perform(get("/owners?page=1").param("lastName", "Unknown Surname"))
|
mockMvc.perform(get("/owners?page=1").param("lastName", "Unknown Surname"))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.samples.petclinic.owner;
|
package org.springframework.samples.petclinic.owner;
|
||||||
|
|
||||||
import org.assertj.core.util.Lists;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Nested;
|
import org.junit.jupiter.api.Nested;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -25,11 +24,14 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
import org.springframework.context.annotation.FilterType;
|
import org.springframework.context.annotation.FilterType;
|
||||||
|
import org.springframework.samples.petclinic.owner.PetTypeRepository;
|
||||||
|
import org.springframework.samples.petclinic.owner.OwnerRepository;
|
||||||
import org.springframework.test.context.aot.DisabledInAotMode;
|
import org.springframework.test.context.aot.DisabledInAotMode;
|
||||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import static org.mockito.BDDMockito.given;
|
import static org.mockito.BDDMockito.given;
|
||||||
|
@ -61,12 +63,15 @@ class PetControllerTests {
|
||||||
@MockitoBean
|
@MockitoBean
|
||||||
private OwnerRepository owners;
|
private OwnerRepository owners;
|
||||||
|
|
||||||
|
@MockitoBean
|
||||||
|
private PetTypeRepository types;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setup() {
|
void setup() {
|
||||||
PetType cat = new PetType();
|
PetType cat = new PetType();
|
||||||
cat.setId(3);
|
cat.setId(3);
|
||||||
cat.setName("hamster");
|
cat.setName("hamster");
|
||||||
given(this.owners.findPetTypes()).willReturn(Lists.newArrayList(cat));
|
given(this.types.findPetTypes()).willReturn(List.of(cat));
|
||||||
|
|
||||||
Owner owner = new Owner();
|
Owner owner = new Owner();
|
||||||
Pet pet = new Pet();
|
Pet pet = new Pet();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -43,13 +43,13 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
class PetTypeFormatterTests {
|
class PetTypeFormatterTests {
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private OwnerRepository pets;
|
private PetTypeRepository types;
|
||||||
|
|
||||||
private PetTypeFormatter petTypeFormatter;
|
private PetTypeFormatter petTypeFormatter;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setup() {
|
void setup() {
|
||||||
this.petTypeFormatter = new PetTypeFormatter(pets);
|
this.petTypeFormatter = new PetTypeFormatter(types);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -62,14 +62,14 @@ class PetTypeFormatterTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldParse() throws ParseException {
|
void shouldParse() throws ParseException {
|
||||||
given(this.pets.findPetTypes()).willReturn(makePetTypes());
|
given(types.findPetTypes()).willReturn(makePetTypes());
|
||||||
PetType petType = petTypeFormatter.parse("Bird", Locale.ENGLISH);
|
PetType petType = petTypeFormatter.parse("Bird", Locale.ENGLISH);
|
||||||
assertThat(petType.getName()).isEqualTo("Bird");
|
assertThat(petType.getName()).isEqualTo("Bird");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldThrowParseException() {
|
void shouldThrowParseException() {
|
||||||
given(this.pets.findPetTypes()).willReturn(makePetTypes());
|
given(types.findPetTypes()).willReturn(makePetTypes());
|
||||||
Assertions.assertThrows(ParseException.class, () -> {
|
Assertions.assertThrows(ParseException.class, () -> {
|
||||||
petTypeFormatter.parse("Fish", Locale.ENGLISH);
|
petTypeFormatter.parse("Fish", Locale.ENGLISH);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -31,6 +31,7 @@ import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.samples.petclinic.owner.Owner;
|
import org.springframework.samples.petclinic.owner.Owner;
|
||||||
import org.springframework.samples.petclinic.owner.OwnerRepository;
|
import org.springframework.samples.petclinic.owner.OwnerRepository;
|
||||||
|
import org.springframework.samples.petclinic.owner.PetTypeRepository;
|
||||||
import org.springframework.samples.petclinic.owner.Pet;
|
import org.springframework.samples.petclinic.owner.Pet;
|
||||||
import org.springframework.samples.petclinic.owner.PetType;
|
import org.springframework.samples.petclinic.owner.PetType;
|
||||||
import org.springframework.samples.petclinic.owner.Visit;
|
import org.springframework.samples.petclinic.owner.Visit;
|
||||||
|
@ -75,6 +76,9 @@ class ClinicServiceTests {
|
||||||
@Autowired
|
@Autowired
|
||||||
protected OwnerRepository owners;
|
protected OwnerRepository owners;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected PetTypeRepository types;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
protected VetRepository vets;
|
protected VetRepository vets;
|
||||||
|
|
||||||
|
@ -140,7 +144,7 @@ class ClinicServiceTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldFindAllPetTypes() {
|
void shouldFindAllPetTypes() {
|
||||||
Collection<PetType> petTypes = this.owners.findPetTypes();
|
Collection<PetType> petTypes = this.types.findPetTypes();
|
||||||
|
|
||||||
PetType petType1 = EntityUtils.getById(petTypes, PetType.class, 1);
|
PetType petType1 = EntityUtils.getById(petTypes, PetType.class, 1);
|
||||||
assertThat(petType1.getName()).isEqualTo("cat");
|
assertThat(petType1.getName()).isEqualTo("cat");
|
||||||
|
@ -159,7 +163,7 @@ class ClinicServiceTests {
|
||||||
|
|
||||||
Pet pet = new Pet();
|
Pet pet = new Pet();
|
||||||
pet.setName("bowser");
|
pet.setName("bowser");
|
||||||
Collection<PetType> types = this.owners.findPetTypes();
|
Collection<PetType> types = this.types.findPetTypes();
|
||||||
pet.setType(EntityUtils.getById(types, PetType.class, 2));
|
pet.setType(EntityUtils.getById(types, PetType.class, 2));
|
||||||
pet.setBirthDate(LocalDate.now());
|
pet.setBirthDate(LocalDate.now());
|
||||||
owner6.addPet(pet);
|
owner6.addPet(pet);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -50,12 +50,6 @@ import org.springframework.http.ResponseEntity;
|
||||||
properties = { "server.error.include-message=ALWAYS", "management.endpoints.enabled-by-default=false" })
|
properties = { "server.error.include-message=ALWAYS", "management.endpoints.enabled-by-default=false" })
|
||||||
class CrashControllerIntegrationTests {
|
class CrashControllerIntegrationTests {
|
||||||
|
|
||||||
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class,
|
|
||||||
DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
|
|
||||||
static class TestConfiguration {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Value(value = "${local.server.port}")
|
@Value(value = "${local.server.port}")
|
||||||
private int port;
|
private int port;
|
||||||
|
|
||||||
|
@ -96,4 +90,10 @@ class CrashControllerIntegrationTests {
|
||||||
"This application has no explicit mapping for");
|
"This application has no explicit mapping for");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class,
|
||||||
|
DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
|
||||||
|
static class TestConfiguration {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
package org.springframework.samples.petclinic.system;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test ensures that there are no hard-coded strings without internationalization in
|
||||||
|
* any HTML files. Also ensures that a string is translated in every language to avoid
|
||||||
|
* partial translations.
|
||||||
|
*
|
||||||
|
* @author Anuj Ashok Potdar
|
||||||
|
*/
|
||||||
|
public class I18nPropertiesSyncTest {
|
||||||
|
|
||||||
|
private static final String I18N_DIR = "src/main/resources";
|
||||||
|
|
||||||
|
private static final String BASE_NAME = "messages";
|
||||||
|
|
||||||
|
public static final String PROPERTIES = ".properties";
|
||||||
|
|
||||||
|
private static final Pattern HTML_TEXT_LITERAL = Pattern.compile(">([^<>{}]+)<");
|
||||||
|
|
||||||
|
private static final Pattern BRACKET_ONLY = Pattern.compile("<[^>]*>\\s*[\\[\\]](?: )?\\s*</[^>]*>");
|
||||||
|
|
||||||
|
private static final Pattern HAS_TH_TEXT_ATTRIBUTE = Pattern.compile("th:(u)?text\\s*=\\s*\"[^\"]+\"");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkNonInternationalizedStrings() throws IOException {
|
||||||
|
Path root = Paths.get("src/main");
|
||||||
|
List<Path> files;
|
||||||
|
|
||||||
|
try (Stream<Path> stream = Files.walk(root)) {
|
||||||
|
files = stream.filter(p -> p.toString().endsWith(".java") || p.toString().endsWith(".html"))
|
||||||
|
.filter(p -> !p.toString().contains("/test/"))
|
||||||
|
.filter(p -> !p.getFileName().toString().endsWith("Test.java"))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder report = new StringBuilder();
|
||||||
|
|
||||||
|
for (Path file : files) {
|
||||||
|
List<String> lines = Files.readAllLines(file);
|
||||||
|
for (int i = 0; i < lines.size(); i++) {
|
||||||
|
String line = lines.get(i).trim();
|
||||||
|
|
||||||
|
if (line.startsWith("//") || line.startsWith("@") || line.contains("log.")
|
||||||
|
|| line.contains("System.out"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (file.toString().endsWith(".html")) {
|
||||||
|
boolean hasLiteralText = HTML_TEXT_LITERAL.matcher(line).find();
|
||||||
|
boolean hasThTextAttribute = HAS_TH_TEXT_ATTRIBUTE.matcher(line).find();
|
||||||
|
boolean isBracketOnly = BRACKET_ONLY.matcher(line).find();
|
||||||
|
|
||||||
|
if (hasLiteralText && !line.contains("#{") && !hasThTextAttribute && !isBracketOnly) {
|
||||||
|
report.append("HTML: ")
|
||||||
|
.append(file)
|
||||||
|
.append(" Line ")
|
||||||
|
.append(i + 1)
|
||||||
|
.append(": ")
|
||||||
|
.append(line)
|
||||||
|
.append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!report.isEmpty()) {
|
||||||
|
fail("Hardcoded (non-internationalized) strings found:\n" + report);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkI18nPropertyFilesAreInSync() throws IOException {
|
||||||
|
List<Path> propertyFiles;
|
||||||
|
try (Stream<Path> stream = Files.walk(Paths.get(I18N_DIR))) {
|
||||||
|
propertyFiles = stream.filter(p -> p.getFileName().toString().startsWith(BASE_NAME))
|
||||||
|
.filter(p -> p.getFileName().toString().endsWith(PROPERTIES))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Properties> localeToProps = new HashMap<>();
|
||||||
|
|
||||||
|
for (Path path : propertyFiles) {
|
||||||
|
Properties props = new Properties();
|
||||||
|
try (var reader = Files.newBufferedReader(path)) {
|
||||||
|
props.load(reader);
|
||||||
|
localeToProps.put(path.getFileName().toString(), props);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String baseFile = BASE_NAME + PROPERTIES;
|
||||||
|
Properties baseProps = localeToProps.get(baseFile);
|
||||||
|
if (baseProps == null) {
|
||||||
|
fail("Base properties file '" + baseFile + "' not found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> baseKeys = baseProps.stringPropertyNames();
|
||||||
|
StringBuilder report = new StringBuilder();
|
||||||
|
|
||||||
|
for (Map.Entry<String, Properties> entry : localeToProps.entrySet()) {
|
||||||
|
String fileName = entry.getKey();
|
||||||
|
// We use fallback logic to include english strings, hence messages_en is not
|
||||||
|
// populated.
|
||||||
|
if (fileName.equals(baseFile) || fileName.equals("messages_en.properties"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Properties props = entry.getValue();
|
||||||
|
Set<String> missingKeys = new TreeSet<>(baseKeys);
|
||||||
|
missingKeys.removeAll(props.stringPropertyNames());
|
||||||
|
|
||||||
|
if (!missingKeys.isEmpty()) {
|
||||||
|
report.append("Missing keys in ").append(fileName).append(":\n");
|
||||||
|
missingKeys.forEach(k -> report.append(" ").append(k).append("\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!report.isEmpty()) {
|
||||||
|
fail("Translation files are not in sync:\n" + report);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
Loading…
Reference in a new issue