├── .editorconfig
├── .gitattributes
├── .gitignore
├── .jhipster
├── Album.json
├── Photo.json
└── Tag.json
├── .mvn
└── wrapper
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── .prettierignore
├── .prettierrc
├── .travis.yml
├── .yo-rc.json
├── LICENSE
├── Procfile
├── README.md
├── gallery.jh
├── mvnw
├── mvnw.cmd
├── package.json
├── pom.xml
├── src
├── main
│ ├── docker
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ ├── app.yml
│ │ ├── entrypoint.sh
│ │ ├── keycloak.yml
│ │ ├── postgresql.yml
│ │ ├── realm-config
│ │ │ ├── jhipster-realm.json
│ │ │ └── jhipster-users-0.json
│ │ └── sonar.yml
│ ├── java
│ │ └── com
│ │ │ └── okta
│ │ │ └── developer
│ │ │ ├── ApplicationWebXml.java
│ │ │ ├── GalleryApp.java
│ │ │ ├── aop
│ │ │ └── logging
│ │ │ │ └── LoggingAspect.java
│ │ │ ├── config
│ │ │ ├── ApplicationProperties.java
│ │ │ ├── AsyncConfiguration.java
│ │ │ ├── CacheConfiguration.java
│ │ │ ├── CloudDatabaseConfiguration.java
│ │ │ ├── Constants.java
│ │ │ ├── DatabaseConfiguration.java
│ │ │ ├── DateTimeFormatConfiguration.java
│ │ │ ├── DefaultProfileUtil.java
│ │ │ ├── JacksonConfiguration.java
│ │ │ ├── LocaleConfiguration.java
│ │ │ ├── LoggingAspectConfiguration.java
│ │ │ ├── LoggingConfiguration.java
│ │ │ ├── MetricsConfiguration.java
│ │ │ ├── OAuth2Configuration.java
│ │ │ ├── SecurityConfiguration.java
│ │ │ ├── WebConfigurer.java
│ │ │ ├── audit
│ │ │ │ ├── AuditEventConverter.java
│ │ │ │ └── package-info.java
│ │ │ └── package-info.java
│ │ │ ├── domain
│ │ │ ├── AbstractAuditingEntity.java
│ │ │ ├── Album.java
│ │ │ ├── Authority.java
│ │ │ ├── PersistentAuditEvent.java
│ │ │ ├── Photo.java
│ │ │ ├── Tag.java
│ │ │ ├── User.java
│ │ │ └── package-info.java
│ │ │ ├── repository
│ │ │ ├── AlbumRepository.java
│ │ │ ├── AuthorityRepository.java
│ │ │ ├── CustomAuditEventRepository.java
│ │ │ ├── PersistenceAuditEventRepository.java
│ │ │ ├── PhotoRepository.java
│ │ │ ├── TagRepository.java
│ │ │ ├── UserRepository.java
│ │ │ └── package-info.java
│ │ │ ├── security
│ │ │ ├── AuthoritiesConstants.java
│ │ │ ├── OAuth2AuthenticationSuccessHandler.java
│ │ │ ├── SecurityUtils.java
│ │ │ ├── SpringSecurityAuditorAware.java
│ │ │ └── package-info.java
│ │ │ ├── service
│ │ │ ├── AuditEventService.java
│ │ │ ├── UserService.java
│ │ │ ├── dto
│ │ │ │ ├── UserDTO.java
│ │ │ │ └── package-info.java
│ │ │ ├── mapper
│ │ │ │ ├── UserMapper.java
│ │ │ │ └── package-info.java
│ │ │ └── package-info.java
│ │ │ └── web
│ │ │ └── rest
│ │ │ ├── AccountResource.java
│ │ │ ├── AlbumResource.java
│ │ │ ├── AuditResource.java
│ │ │ ├── LogsResource.java
│ │ │ ├── PhotoResource.java
│ │ │ ├── TagResource.java
│ │ │ ├── UserResource.java
│ │ │ ├── errors
│ │ │ ├── BadRequestAlertException.java
│ │ │ ├── CustomParameterizedException.java
│ │ │ ├── EmailAlreadyUsedException.java
│ │ │ ├── EmailNotFoundException.java
│ │ │ ├── ErrorConstants.java
│ │ │ ├── ExceptionTranslator.java
│ │ │ ├── FieldErrorVM.java
│ │ │ ├── InternalServerErrorException.java
│ │ │ ├── InvalidPasswordException.java
│ │ │ ├── LoginAlreadyUsedException.java
│ │ │ └── package-info.java
│ │ │ ├── package-info.java
│ │ │ ├── util
│ │ │ ├── HeaderUtil.java
│ │ │ └── PaginationUtil.java
│ │ │ └── vm
│ │ │ ├── LoggerVM.java
│ │ │ ├── ManagedUserVM.java
│ │ │ └── package-info.java
│ ├── resources
│ │ ├── .h2.server.properties
│ │ ├── banner.txt
│ │ ├── config
│ │ │ ├── application-dev.yml
│ │ │ ├── application-heroku.yml
│ │ │ ├── application-prod.yml
│ │ │ ├── application.yml
│ │ │ ├── bootstrap-heroku.yml
│ │ │ └── liquibase
│ │ │ │ ├── authorities.csv
│ │ │ │ ├── changelog
│ │ │ │ ├── 00000000000000_initial_schema.xml
│ │ │ │ ├── 20180625042224_added_entity_Album.xml
│ │ │ │ ├── 20180625042224_added_entity_constraints_Album.xml
│ │ │ │ ├── 20180625042225_added_entity_Photo.xml
│ │ │ │ ├── 20180625042225_added_entity_constraints_Photo.xml
│ │ │ │ └── 20180625042226_added_entity_Tag.xml
│ │ │ │ ├── master.xml
│ │ │ │ ├── users.csv
│ │ │ │ └── users_authorities.csv
│ │ ├── i18n
│ │ │ ├── messages.properties
│ │ │ ├── messages_en.properties
│ │ │ └── messages_fr.properties
│ │ ├── logback-spring.xml
│ │ └── templates
│ │ │ └── error.html
│ └── webapp
│ │ ├── 404.html
│ │ ├── app
│ │ ├── app.css
│ │ ├── app.tsx
│ │ ├── config
│ │ │ ├── axios-interceptor.ts
│ │ │ ├── constants.ts
│ │ │ ├── devtools.tsx
│ │ │ ├── error-middleware.ts
│ │ │ ├── icon-loader.ts
│ │ │ ├── logger-middleware.ts
│ │ │ ├── notification-middleware.ts
│ │ │ ├── store.ts
│ │ │ └── translation.ts
│ │ ├── entities
│ │ │ ├── album
│ │ │ │ ├── album-delete-dialog.tsx
│ │ │ │ ├── album-detail.tsx
│ │ │ │ ├── album-update.tsx
│ │ │ │ ├── album.reducer.ts
│ │ │ │ ├── album.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── index.tsx
│ │ │ ├── photo
│ │ │ │ ├── index.tsx
│ │ │ │ ├── photo-delete-dialog.tsx
│ │ │ │ ├── photo-detail.tsx
│ │ │ │ ├── photo-update.tsx
│ │ │ │ ├── photo.reducer.ts
│ │ │ │ └── photo.tsx
│ │ │ └── tag
│ │ │ │ ├── index.tsx
│ │ │ │ ├── tag-delete-dialog.tsx
│ │ │ │ ├── tag-detail.tsx
│ │ │ │ ├── tag-update.tsx
│ │ │ │ ├── tag.reducer.ts
│ │ │ │ └── tag.tsx
│ │ ├── index.tsx
│ │ ├── modules
│ │ │ ├── administration
│ │ │ │ ├── administration.reducer.ts
│ │ │ │ ├── audits
│ │ │ │ │ └── audits.tsx
│ │ │ │ ├── configuration
│ │ │ │ │ └── configuration.tsx
│ │ │ │ ├── docs
│ │ │ │ │ └── docs.tsx
│ │ │ │ ├── health
│ │ │ │ │ ├── health-modal.tsx
│ │ │ │ │ └── health.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── logs
│ │ │ │ │ └── logs.tsx
│ │ │ │ └── metrics
│ │ │ │ │ ├── metrics-modal.tsx
│ │ │ │ │ ├── metrics.tsx
│ │ │ │ │ └── thread-item.tsx
│ │ │ ├── home
│ │ │ │ ├── home.css
│ │ │ │ └── home.tsx
│ │ │ └── login
│ │ │ │ └── logout.tsx
│ │ ├── routes.tsx
│ │ ├── shared
│ │ │ ├── auth
│ │ │ │ └── private-route.tsx
│ │ │ ├── error
│ │ │ │ ├── error-boundary-route.tsx
│ │ │ │ └── error-boundary.tsx
│ │ │ ├── layout
│ │ │ │ ├── footer
│ │ │ │ │ ├── footer.css
│ │ │ │ │ └── footer.tsx
│ │ │ │ ├── header
│ │ │ │ │ ├── header-components.tsx
│ │ │ │ │ ├── header.css
│ │ │ │ │ ├── header.tsx
│ │ │ │ │ └── menus
│ │ │ │ │ │ ├── account.tsx
│ │ │ │ │ │ ├── admin.tsx
│ │ │ │ │ │ ├── entities.tsx
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── locale.tsx
│ │ │ │ └── password
│ │ │ │ │ ├── password-strength-bar.css
│ │ │ │ │ └── password-strength-bar.tsx
│ │ │ ├── model
│ │ │ │ ├── album.model.ts
│ │ │ │ ├── photo.model.ts
│ │ │ │ ├── tag.model.ts
│ │ │ │ └── user.model.ts
│ │ │ ├── reducers
│ │ │ │ ├── action-type.util.ts
│ │ │ │ ├── application-profile.ts
│ │ │ │ ├── authentication.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── locale.ts
│ │ │ │ └── user-management.ts
│ │ │ └── util
│ │ │ │ ├── date-utils.ts
│ │ │ │ ├── entity-utils.ts
│ │ │ │ ├── pagination.constants.ts
│ │ │ │ └── url-utils.ts
│ │ └── typings.d.ts
│ │ ├── favicon.ico
│ │ ├── i18n
│ │ ├── en
│ │ │ ├── activate.json
│ │ │ ├── album.json
│ │ │ ├── audits.json
│ │ │ ├── configuration.json
│ │ │ ├── error.json
│ │ │ ├── gateway.json
│ │ │ ├── global.json
│ │ │ ├── health.json
│ │ │ ├── home.json
│ │ │ ├── login.json
│ │ │ ├── logs.json
│ │ │ ├── metrics.json
│ │ │ ├── password.json
│ │ │ ├── photo.json
│ │ │ ├── register.json
│ │ │ ├── reset.json
│ │ │ ├── sessions.json
│ │ │ ├── settings.json
│ │ │ ├── tag.json
│ │ │ └── user-management.json
│ │ └── fr
│ │ │ ├── activate.json
│ │ │ ├── album.json
│ │ │ ├── audits.json
│ │ │ ├── configuration.json
│ │ │ ├── error.json
│ │ │ ├── gateway.json
│ │ │ ├── global.json
│ │ │ ├── health.json
│ │ │ ├── home.json
│ │ │ ├── login.json
│ │ │ ├── logs.json
│ │ │ ├── metrics.json
│ │ │ ├── password.json
│ │ │ ├── photo.json
│ │ │ ├── register.json
│ │ │ ├── reset.json
│ │ │ ├── sessions.json
│ │ │ ├── settings.json
│ │ │ ├── tag.json
│ │ │ └── user-management.json
│ │ ├── index.html
│ │ ├── manifest.webapp
│ │ ├── robots.txt
│ │ ├── static
│ │ └── images
│ │ │ ├── hipster.png
│ │ │ ├── hipster192.png
│ │ │ ├── hipster256.png
│ │ │ ├── hipster2x.png
│ │ │ ├── hipster384.png
│ │ │ ├── hipster512.png
│ │ │ ├── logo-jhipster-react.svg
│ │ │ └── logo-jhipster.png
│ │ └── swagger-ui
│ │ ├── dist
│ │ └── images
│ │ │ └── throbber.gif
│ │ └── index.html
└── test
│ ├── java
│ └── com
│ │ └── okta
│ │ └── developer
│ │ ├── config
│ │ ├── WebConfigurerTest.java
│ │ └── WebConfigurerTestController.java
│ │ ├── repository
│ │ └── CustomAuditEventRepositoryIntTest.java
│ │ ├── security
│ │ └── SecurityUtilsUnitTest.java
│ │ ├── service
│ │ └── UserServiceIntTest.java
│ │ └── web
│ │ └── rest
│ │ ├── AccountResourceIntTest.java
│ │ ├── AlbumResourceIntTest.java
│ │ ├── AuditResourceIntTest.java
│ │ ├── LogsResourceIntTest.java
│ │ ├── PhotoResourceIntTest.java
│ │ ├── TagResourceIntTest.java
│ │ ├── TestUtil.java
│ │ ├── UserResourceIntTest.java
│ │ ├── errors
│ │ ├── ExceptionTranslatorIntTest.java
│ │ └── ExceptionTranslatorTestController.java
│ │ └── util
│ │ └── PaginationUtilUnitTest.java
│ ├── javascript
│ ├── e2e
│ │ ├── entities
│ │ │ ├── album
│ │ │ │ ├── album-update.page-object.ts
│ │ │ │ ├── album.page-object.ts
│ │ │ │ └── album.spec.ts
│ │ │ ├── photo
│ │ │ │ ├── photo-update.page-object.ts
│ │ │ │ ├── photo.page-object.ts
│ │ │ │ └── photo.spec.ts
│ │ │ └── tag
│ │ │ │ ├── tag-update.page-object.ts
│ │ │ │ ├── tag.page-object.ts
│ │ │ │ └── tag.spec.ts
│ │ ├── modules
│ │ │ ├── account
│ │ │ │ └── account.spec.ts
│ │ │ └── administration
│ │ │ │ └── administration.spec.ts
│ │ ├── page-objects
│ │ │ ├── base-component.ts
│ │ │ ├── navbar-page.ts
│ │ │ └── signin-page.ts
│ │ └── util
│ │ │ └── utils.ts
│ ├── enzyme-setup.ts
│ ├── jest.conf.js
│ ├── protractor.conf.js
│ ├── spec
│ │ └── app
│ │ │ ├── config
│ │ │ └── notification-middleware.spec.ts
│ │ │ ├── entities
│ │ │ ├── album
│ │ │ │ └── album-reducer.spec.ts
│ │ │ ├── photo
│ │ │ │ └── photo-reducer.spec.ts
│ │ │ └── tag
│ │ │ │ └── tag-reducer.spec.ts
│ │ │ ├── modules
│ │ │ └── administration
│ │ │ │ └── administration.reducer.spec.ts
│ │ │ ├── shared
│ │ │ ├── auth
│ │ │ │ └── private-route.spec.tsx
│ │ │ ├── error
│ │ │ │ ├── error-boundary-route.spec.tsx
│ │ │ │ └── error-boundary.spec.tsx
│ │ │ ├── layout
│ │ │ │ └── header
│ │ │ │ │ ├── header.spec.tsx
│ │ │ │ │ └── menus
│ │ │ │ │ └── account.spec.tsx
│ │ │ ├── reducers
│ │ │ │ ├── application-profile.spec.ts
│ │ │ │ ├── authentication.spec.ts
│ │ │ │ └── user-management.spec.ts
│ │ │ └── util
│ │ │ │ └── entity-utils.spec.ts
│ │ │ └── utils.ts
│ ├── storage-mock.ts
│ └── tsconfig.e2e.json
│ └── resources
│ ├── config
│ └── application.yml
│ └── logback.xml
├── tsconfig.json
├── tslint.json
├── webpack
├── logo-jhipster.png
├── utils.js
├── webpack.common.js
├── webpack.dev.js
└── webpack.prod.js
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 | [*]
8 |
9 | # Change these settings to your own preference
10 | indent_style = space
11 | indent_size = 4
12 | max_line_length = 180
13 |
14 | # We recommend you to keep these unchanged
15 | end_of_line = lf
16 | charset = utf-8
17 | trim_trailing_whitespace = true
18 | insert_final_newline = true
19 |
20 | [*.{ts,tsx,js,jsx,json,css,scss,sql,ejs}]
21 | indent_style = space
22 | indent_size = 2
23 |
24 | [*.md]
25 | trim_trailing_whitespace = false
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ######################
2 | # Project Specific
3 | ######################
4 | /target/www/**
5 | /src/test/javascript/coverage/
6 |
7 | ######################
8 | # Node
9 | ######################
10 | /node/
11 | node_tmp/
12 | node_modules/
13 | npm-debug.log.*
14 | /.awcache/*
15 | /.cache-loader/*
16 |
17 | ######################
18 | # SASS
19 | ######################
20 | .sass-cache/
21 |
22 | ######################
23 | # Eclipse
24 | ######################
25 | *.pydevproject
26 | .project
27 | .metadata
28 | tmp/
29 | tmp/**/*
30 | *.tmp
31 | *.bak
32 | *.swp
33 | *~.nib
34 | local.properties
35 | .classpath
36 | .settings/
37 | .loadpath
38 | .factorypath
39 | /src/main/resources/rebel.xml
40 |
41 | # External tool builders
42 | .externalToolBuilders/**
43 |
44 | # Locally stored "Eclipse launch configurations"
45 | *.launch
46 |
47 | # CDT-specific
48 | .cproject
49 |
50 | # PDT-specific
51 | .buildpath
52 |
53 | ######################
54 | # Intellij
55 | ######################
56 | .idea/
57 | *.iml
58 | *.iws
59 | *.ipr
60 | *.ids
61 | *.orig
62 | classes/
63 | out/
64 |
65 | ######################
66 | # Visual Studio Code
67 | ######################
68 | .vscode/
69 |
70 | ######################
71 | # Maven
72 | ######################
73 | /log/
74 | /target/
75 |
76 | ######################
77 | # Gradle
78 | ######################
79 | .gradle/
80 | /build/
81 |
82 | ######################
83 | # Package Files
84 | ######################
85 | *.jar
86 | *.war
87 | *.ear
88 | *.db
89 |
90 | ######################
91 | # Windows
92 | ######################
93 | # Windows image file caches
94 | Thumbs.db
95 |
96 | # Folder config file
97 | Desktop.ini
98 |
99 | ######################
100 | # Mac OSX
101 | ######################
102 | .DS_Store
103 | .svn
104 |
105 | # Thumbnails
106 | ._*
107 |
108 | # Files that might appear on external disk
109 | .Spotlight-V100
110 | .Trashes
111 |
112 | ######################
113 | # Directories
114 | ######################
115 | /bin/
116 | /deploy/
117 |
118 | ######################
119 | # Logs
120 | ######################
121 | *.log*
122 |
123 | ######################
124 | # Others
125 | ######################
126 | *.class
127 | *.*~
128 | *~
129 | .merge_file*
130 |
131 | ######################
132 | # Gradle Wrapper
133 | ######################
134 | !gradle/wrapper/gradle-wrapper.jar
135 |
136 | ######################
137 | # Maven Wrapper
138 | ######################
139 | !.mvn/wrapper/maven-wrapper.jar
140 |
141 | ######################
142 | # ESLint
143 | ######################
144 | .eslintcache
145 |
--------------------------------------------------------------------------------
/.jhipster/Album.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Album",
3 | "fields": [
4 | {
5 | "fieldName": "title",
6 | "fieldType": "String",
7 | "fieldValidateRules": [
8 | "required"
9 | ]
10 | },
11 | {
12 | "fieldName": "description",
13 | "fieldType": "byte[]",
14 | "fieldTypeBlobContent": "text"
15 | },
16 | {
17 | "fieldName": "created",
18 | "fieldType": "Instant"
19 | }
20 | ],
21 | "relationships": [
22 | {
23 | "relationshipType": "many-to-one",
24 | "relationshipName": "user",
25 | "otherEntityName": "user",
26 | "otherEntityField": "login"
27 | }
28 | ],
29 | "changelogDate": "20180625042224",
30 | "entityTableName": "album",
31 | "dto": "no",
32 | "pagination": "pagination",
33 | "service": "no",
34 | "jpaMetamodelFiltering": false,
35 | "fluentMethods": true,
36 | "clientRootFolder": "",
37 | "applications": "*"
38 | }
--------------------------------------------------------------------------------
/.jhipster/Photo.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Photo",
3 | "fields": [
4 | {
5 | "fieldName": "title",
6 | "fieldType": "String",
7 | "fieldValidateRules": [
8 | "required"
9 | ]
10 | },
11 | {
12 | "fieldName": "description",
13 | "fieldType": "byte[]",
14 | "fieldTypeBlobContent": "text"
15 | },
16 | {
17 | "fieldName": "image",
18 | "fieldType": "byte[]",
19 | "fieldTypeBlobContent": "image",
20 | "fieldValidateRules": [
21 | "required"
22 | ]
23 | },
24 | {
25 | "fieldName": "height",
26 | "fieldType": "Integer"
27 | },
28 | {
29 | "fieldName": "width",
30 | "fieldType": "Integer"
31 | },
32 | {
33 | "fieldName": "taken",
34 | "fieldType": "Instant"
35 | },
36 | {
37 | "fieldName": "uploaded",
38 | "fieldType": "Instant"
39 | }
40 | ],
41 | "relationships": [
42 | {
43 | "relationshipType": "many-to-one",
44 | "relationshipName": "album",
45 | "otherEntityName": "album",
46 | "otherEntityField": "title"
47 | },
48 | {
49 | "relationshipType": "many-to-many",
50 | "otherEntityRelationshipName": "photo",
51 | "relationshipName": "tag",
52 | "otherEntityName": "tag",
53 | "otherEntityField": "name",
54 | "ownerSide": true
55 | }
56 | ],
57 | "changelogDate": "20180625042225",
58 | "entityTableName": "photo",
59 | "dto": "no",
60 | "pagination": "infinite-scroll",
61 | "service": "no",
62 | "jpaMetamodelFiltering": false,
63 | "fluentMethods": true,
64 | "clientRootFolder": "",
65 | "applications": "*"
66 | }
--------------------------------------------------------------------------------
/.jhipster/Tag.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Tag",
3 | "fields": [
4 | {
5 | "fieldName": "name",
6 | "fieldType": "String",
7 | "fieldValidateRules": [
8 | "required",
9 | "minlength"
10 | ],
11 | "fieldValidateRulesMinlength": 2
12 | }
13 | ],
14 | "relationships": [
15 | {
16 | "relationshipType": "many-to-many",
17 | "relationshipName": "photo",
18 | "otherEntityName": "photo",
19 | "ownerSide": false,
20 | "otherEntityRelationshipName": "tag"
21 | }
22 | ],
23 | "changelogDate": "20180625042226",
24 | "entityTableName": "tag",
25 | "dto": "no",
26 | "pagination": "infinite-scroll",
27 | "service": "no",
28 | "jpaMetamodelFiltering": false,
29 | "fluentMethods": true,
30 | "clientRootFolder": "",
31 | "applications": "*"
32 | }
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oktadev/okta-react-photo-gallery-example/c0ba0bbfbcd66ca20c7a2637e8fbf6a18892a0f3/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip
2 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | target
3 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | # Prettier configuration
2 |
3 | printWidth: 140
4 | singleQuote: true
5 | tabWidth: 2
6 | useTabs: false
7 |
8 | # js and ts rules:
9 | arrowParens: avoid
10 |
11 | # jsx and tsx rules:
12 | jsxBracketSameLine: false
13 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | os:
2 | - linux
3 | services:
4 | - docker
5 | language: node_js
6 | node_js:
7 | - 8.11.2
8 | jdk:
9 | - oraclejdk8
10 | sudo: false
11 | cache:
12 | directories:
13 | - node
14 | - node_modules
15 | - "$HOME/.m2"
16 | - "$HOME/.yarn-cache"
17 | env:
18 | global:
19 | - NODE_VERSION=8.11.2
20 | - SPRING_OUTPUT_ANSI_ENABLED=ALWAYS
21 | - SPRING_JPA_SHOW_SQL=false
22 | before_install:
23 | - jdk_switcher use oraclejdk8
24 | - java -version
25 | - sudo /etc/init.d/mysql stop
26 | - sudo /etc/init.d/postgresql stop
27 | - curl -o- -L https://yarnpkg.com/install.sh | bash
28 | - export PATH=$HOME/.yarn/bin:$PATH
29 | install:
30 | - yarn install
31 | script:
32 | - chmod +x mvnw
33 | - "./mvnw clean test"
34 | - yarn test
35 | notifications:
36 | webhooks:
37 | on_success: change
38 | on_failure: always
39 | on_start: false
--------------------------------------------------------------------------------
/.yo-rc.json:
--------------------------------------------------------------------------------
1 | {
2 | "generator-jhipster": {
3 | "promptValues": {
4 | "packageName": "com.okta.developer",
5 | "nativeLanguage": "en"
6 | },
7 | "jhipsterVersion": "5.0.1",
8 | "applicationType": "monolith",
9 | "baseName": "gallery",
10 | "packageName": "com.okta.developer",
11 | "packageFolder": "com/okta/developer",
12 | "serverPort": "8080",
13 | "authenticationType": "oauth2",
14 | "cacheProvider": "ehcache",
15 | "enableHibernateCache": true,
16 | "websocket": false,
17 | "databaseType": "sql",
18 | "devDatabaseType": "h2Disk",
19 | "prodDatabaseType": "postgresql",
20 | "searchEngine": false,
21 | "messageBroker": false,
22 | "serviceDiscoveryType": false,
23 | "buildTool": "maven",
24 | "enableSwaggerCodegen": false,
25 | "clientFramework": "react",
26 | "useSass": false,
27 | "clientPackageManager": "yarn",
28 | "testFrameworks": [
29 | "protractor"
30 | ],
31 | "jhiPrefix": "jhi",
32 | "enableTranslation": true,
33 | "nativeLanguage": "en",
34 | "languages": [
35 | "en",
36 | "fr"
37 | ],
38 | "herokuDeployType": "git",
39 | "herokuAppName": "gallery-pwa"
40 | }
41 | }
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: java $JAVA_OPTS -Xmx256m -jar target/*.war --spring.profiles.active=prod,heroku --server.port=$PORT
2 |
--------------------------------------------------------------------------------
/gallery.jh:
--------------------------------------------------------------------------------
1 | entity Album {
2 | title String required,
3 | description TextBlob,
4 | created Instant
5 | }
6 |
7 | entity Photo {
8 | title String required,
9 | description TextBlob,
10 | image ImageBlob required,
11 | height Integer,
12 | width Integer,
13 | taken Instant,
14 | uploaded Instant
15 | }
16 |
17 | entity Tag {
18 | name String required minlength(2)
19 | }
20 |
21 | relationship ManyToOne {
22 | Album{user(login)} to User,
23 | Photo{album(title)} to Album
24 | }
25 |
26 | relationship ManyToMany {
27 | Photo{tag(name)} to Tag{photo}
28 | }
29 |
30 | paginate Album with pagination
31 | paginate Photo, Tag with infinite-scroll
32 |
--------------------------------------------------------------------------------
/src/main/docker/.dockerignore:
--------------------------------------------------------------------------------
1 | # https://docs.docker.com/engine/reference/builder/#dockerignore-file
2 | classes/
3 | generated-sources/
4 | generated-test-sources/
5 | h2db/
6 | maven-archiver/
7 | maven-status/
8 | reports/
9 | surefire-reports/
10 | test-classes/
11 | test-results/
12 | www/
13 | !*.jar
14 | !*.war
15 |
--------------------------------------------------------------------------------
/src/main/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openjdk:8-jre-alpine
2 |
3 | ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \
4 | JHIPSTER_SLEEP=0 \
5 | JAVA_OPTS=""
6 |
7 | # Add a jhipster user to run our application so that it doesn't need to run as root
8 | RUN adduser -D -s /bin/sh jhipster
9 | WORKDIR /home/jhipster
10 |
11 | ADD entrypoint.sh entrypoint.sh
12 | RUN chmod 755 entrypoint.sh && chown jhipster:jhipster entrypoint.sh
13 | USER jhipster
14 |
15 | ADD *.war app.war
16 |
17 | ENTRYPOINT ["./entrypoint.sh"]
18 |
19 | EXPOSE 8080
20 |
21 |
--------------------------------------------------------------------------------
/src/main/docker/app.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 | gallery-app:
4 | image: gallery
5 | environment:
6 | # - _JAVA_OPTIONS=-Xmx512m -Xms256m
7 | - SPRING_PROFILES_ACTIVE=prod,swagger
8 | - SPRING_DATASOURCE_URL=jdbc:postgresql://gallery-postgresql:5432/gallery
9 | - SECURITY_OAUTH2_CLIENT_ACCESS_TOKEN_URI=http://keycloak:9080/auth/realms/jhipster/protocol/openid-connect/token
10 | - SECURITY_OAUTH2_CLIENT_USER_AUTHORIZATION_URI=http://keycloak:9080/auth/realms/jhipster/protocol/openid-connect/auth
11 | - SECURITY_OAUTH2_CLIENT_CLIENT_ID=web_app
12 | - SECURITY_OAUTH2_CLIENT_CLIENT_SECRET=web_app
13 | - SECURITY_OAUTH2_CLIENT_SCOPE=openid profile email
14 | - SECURITY_OAUTH2_RESOURCE_USER_INFO_URI=http://keycloak:9080/auth/realms/jhipster/protocol/openid-connect/userinfo
15 | - JHIPSTER_SLEEP=10 # gives time for the database to boot before the application
16 | ports:
17 | - 8080:8080
18 | gallery-postgresql:
19 | extends:
20 | file: postgresql.yml
21 | service: gallery-postgresql
22 | keycloak:
23 | extends:
24 | file: keycloak.yml
25 | service: keycloak
26 |
--------------------------------------------------------------------------------
/src/main/docker/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | echo "The application will start in ${JHIPSTER_SLEEP}s..." && sleep ${JHIPSTER_SLEEP}
4 | exec java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar "${HOME}/app.war" "$@"
5 |
--------------------------------------------------------------------------------
/src/main/docker/keycloak.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 | keycloak:
4 | image: jboss/keycloak:4.0.0.Final
5 | command: ["-b", "0.0.0.0", "-Dkeycloak.migration.action=import", "-Dkeycloak.migration.provider=dir", "-Dkeycloak.migration.dir=/opt/jboss/keycloak/realm-config", "-Dkeycloak.migration.strategy=OVERWRITE_EXISTING", "-Djboss.socket.binding.port-offset=1000"]
6 | volumes:
7 | - ./realm-config:/opt/jboss/keycloak/realm-config
8 | environment:
9 | - KEYCLOAK_USER=admin
10 | - KEYCLOAK_PASSWORD=admin
11 | - DB_VENDOR=h2
12 | ports:
13 | - 9080:9080
14 | - 9443:9443
15 | - 10990:10990
16 |
--------------------------------------------------------------------------------
/src/main/docker/postgresql.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 | gallery-postgresql:
4 | image: postgres:10.4
5 | # volumes:
6 | # - ~/volumes/jhipster/gallery/postgresql/:/var/lib/postgresql/data/
7 | environment:
8 | - POSTGRES_USER=gallery
9 | - POSTGRES_PASSWORD=
10 | ports:
11 | - 5432:5432
12 |
--------------------------------------------------------------------------------
/src/main/docker/realm-config/jhipster-users-0.json:
--------------------------------------------------------------------------------
1 | {
2 | "realm" : "jhipster",
3 | "users" : [ {
4 | "id" : "4c973896-5761-41fc-8217-07c5d13a004b",
5 | "createdTimestamp" : 1505479415590,
6 | "username" : "admin",
7 | "enabled" : true,
8 | "totp" : false,
9 | "emailVerified" : true,
10 | "firstName" : "Admin",
11 | "lastName" : "Administrator",
12 | "email" : "admin@localhost",
13 | "credentials" : [ {
14 | "type" : "password",
15 | "hashedSaltedValue" : "4pf9K2jWSCcHC+CwsZP/qidN5pSmDUe6AX6wBerSGdBVKkExay8MWKx+EKmaaObZW6FVsD8vdW/ZsyUFD9gJ1Q==",
16 | "salt" : "1/qNkZ5kr77jOMOBPBogGw==",
17 | "hashIterations" : 27500,
18 | "counter" : 0,
19 | "algorithm" : "pbkdf2-sha256",
20 | "digits" : 0,
21 | "period" : 0,
22 | "createdDate" : 1505479429154,
23 | "config" : { }
24 | } ],
25 | "disableableCredentialTypes" : [ "password" ],
26 | "requiredActions" : [ ],
27 | "realmRoles" : [ "offline_access", "uma_authorization" ],
28 | "clientRoles" : {
29 | "account" : [ "view-profile", "manage-account" ]
30 | },
31 | "notBefore" : 0,
32 | "groups" : [ "/Users", "/Admins" ]
33 | }, {
34 | "id" : "c4af4e2f-b432-4c3b-8405-cca86cd5b97b",
35 | "createdTimestamp" : 1505479373742,
36 | "username" : "user",
37 | "enabled" : true,
38 | "totp" : false,
39 | "emailVerified" : true,
40 | "firstName" : "",
41 | "lastName" : "User",
42 | "email" : "user@localhost",
43 | "credentials" : [ {
44 | "type" : "password",
45 | "hashedSaltedValue" : "MbKsMgWPnZyImih8s4SaoCSCq+XIY/c6S9F93sXEidHF1TjPWxCqMkec0+o3860CMLXHt3az61cIJOWI0FW9aw==",
46 | "salt" : "fmpBI1r8R1u75hDLMUlwBw==",
47 | "hashIterations" : 27500,
48 | "counter" : 0,
49 | "algorithm" : "pbkdf2-sha256",
50 | "digits" : 0,
51 | "period" : 0,
52 | "createdDate" : 1505479392766,
53 | "config" : { }
54 | } ],
55 | "disableableCredentialTypes" : [ "password" ],
56 | "requiredActions" : [ ],
57 | "realmRoles" : [ "offline_access", "uma_authorization" ],
58 | "clientRoles" : {
59 | "account" : [ "view-profile", "manage-account" ]
60 | },
61 | "notBefore" : 0,
62 | "groups" : [ "/Users" ]
63 | } ]
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/docker/sonar.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 | gallery-sonar:
4 | image: sonarqube:7.1-alpine
5 | ports:
6 | - 9000:9000
7 | - 9092:9092
8 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/ApplicationWebXml.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer;
2 |
3 | import com.okta.developer.config.DefaultProfileUtil;
4 | import org.springframework.boot.builder.SpringApplicationBuilder;
5 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
6 |
7 | /**
8 | * This is a helper Java class that provides an alternative to creating a web.xml.
9 | * This will be invoked only when the application is deployed to a Servlet container like Tomcat, JBoss etc.
10 | */
11 | public class ApplicationWebXml extends SpringBootServletInitializer {
12 |
13 | @Override
14 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
15 | /**
16 | * set a default to use when no profile is configured.
17 | */
18 | DefaultProfileUtil.addDefaultProfile(application.application());
19 | return application.sources(GalleryApp.class);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/config/ApplicationProperties.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.config;
2 |
3 | import org.springframework.boot.context.properties.ConfigurationProperties;
4 |
5 | /**
6 | * Properties specific to Gallery.
7 | *
8 | * Properties are configured in the application.yml file.
9 | * See {@link io.github.jhipster.config.JHipsterProperties} for a good example.
10 | */
11 | @ConfigurationProperties(prefix = "application", ignoreUnknownFields = false)
12 | public class ApplicationProperties {
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/config/AsyncConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.config;
2 |
3 | import io.github.jhipster.async.ExceptionHandlingAsyncTaskExecutor;
4 | import io.github.jhipster.config.JHipsterProperties;
5 |
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
9 | import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
10 | import org.springframework.context.annotation.Bean;
11 | import org.springframework.context.annotation.Configuration;
12 | import org.springframework.scheduling.annotation.*;
13 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
14 |
15 | import java.util.concurrent.Executor;
16 |
17 | @Configuration
18 | @EnableAsync
19 | @EnableScheduling
20 | public class AsyncConfiguration implements AsyncConfigurer {
21 |
22 | private final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class);
23 |
24 | private final JHipsterProperties jHipsterProperties;
25 |
26 | public AsyncConfiguration(JHipsterProperties jHipsterProperties) {
27 | this.jHipsterProperties = jHipsterProperties;
28 | }
29 |
30 | @Override
31 | @Bean(name = "taskExecutor")
32 | public Executor getAsyncExecutor() {
33 | log.debug("Creating Async Task Executor");
34 | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
35 | executor.setCorePoolSize(jHipsterProperties.getAsync().getCorePoolSize());
36 | executor.setMaxPoolSize(jHipsterProperties.getAsync().getMaxPoolSize());
37 | executor.setQueueCapacity(jHipsterProperties.getAsync().getQueueCapacity());
38 | executor.setThreadNamePrefix("gallery-Executor-");
39 | return new ExceptionHandlingAsyncTaskExecutor(executor);
40 | }
41 |
42 | @Override
43 | public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
44 | return new SimpleAsyncUncaughtExceptionHandler();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/config/CloudDatabaseConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.config;
2 |
3 | import io.github.jhipster.config.JHipsterConstants;
4 |
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.cloud.config.java.AbstractCloudConfig;
8 | import org.springframework.context.annotation.*;
9 |
10 | import javax.sql.DataSource;
11 |
12 | @Configuration
13 | @Profile(JHipsterConstants.SPRING_PROFILE_CLOUD)
14 | public class CloudDatabaseConfiguration extends AbstractCloudConfig {
15 |
16 | private final Logger log = LoggerFactory.getLogger(CloudDatabaseConfiguration.class);
17 |
18 | @Bean
19 | public DataSource dataSource() {
20 | log.info("Configuring JDBC datasource from a cloud provider");
21 | return connectionFactory().dataSource();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/config/Constants.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.config;
2 |
3 | /**
4 | * Application constants.
5 | */
6 | public final class Constants {
7 |
8 | // Regex for acceptable logins
9 | public static final String LOGIN_REGEX = "^[_.@A-Za-z0-9-]*$";
10 |
11 | public static final String SYSTEM_ACCOUNT = "system";
12 | public static final String ANONYMOUS_USER = "anonymoususer";
13 | public static final String DEFAULT_LANGUAGE = "en";
14 |
15 | private Constants() {
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/config/DateTimeFormatConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.config;
2 |
3 | import org.springframework.context.annotation.Configuration;
4 | import org.springframework.format.FormatterRegistry;
5 | import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar;
6 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
7 |
8 | @Configuration
9 | public class DateTimeFormatConfiguration implements WebMvcConfigurer {
10 |
11 | @Override
12 | public void addFormatters(FormatterRegistry registry) {
13 | DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
14 | registrar.setUseIsoFormat(true);
15 | registrar.registerFormatters(registry);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/config/DefaultProfileUtil.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.config;
2 |
3 | import io.github.jhipster.config.JHipsterConstants;
4 |
5 | import org.springframework.boot.SpringApplication;
6 | import org.springframework.core.env.Environment;
7 |
8 | import java.util.*;
9 |
10 | /**
11 | * Utility class to load a Spring profile to be used as default
12 | * when there is no spring.profiles.active set in the environment or as command line argument.
13 | * If the value is not available in application.yml then dev profile will be used as default.
14 | */
15 | public final class DefaultProfileUtil {
16 |
17 | private static final String SPRING_PROFILE_DEFAULT = "spring.profiles.default";
18 |
19 | private DefaultProfileUtil() {
20 | }
21 |
22 | /**
23 | * Set a default to use when no profile is configured.
24 | *
25 | * @param app the Spring application
26 | */
27 | public static void addDefaultProfile(SpringApplication app) {
28 | Map defProperties = new HashMap<>();
29 | /*
30 | * The default profile to use when no other profiles are defined
31 | * This cannot be set in the application.yml file.
32 | * See https://github.com/spring-projects/spring-boot/issues/1219
33 | */
34 | defProperties.put(SPRING_PROFILE_DEFAULT, JHipsterConstants.SPRING_PROFILE_DEVELOPMENT);
35 | app.setDefaultProperties(defProperties);
36 | }
37 |
38 | /**
39 | * Get the profiles that are applied else get default profiles.
40 | *
41 | * @param env spring environment
42 | * @return profiles
43 | */
44 | public static String[] getActiveProfiles(Environment env) {
45 | String[] profiles = env.getActiveProfiles();
46 | if (profiles.length == 0) {
47 | return env.getDefaultProfiles();
48 | }
49 | return profiles;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/config/JacksonConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.config;
2 |
3 | import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
4 | import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
5 |
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.context.annotation.Configuration;
8 | import org.zalando.problem.ProblemModule;
9 | import org.zalando.problem.validation.ConstraintViolationProblemModule;
10 |
11 | @Configuration
12 | public class JacksonConfiguration {
13 |
14 | /*
15 | * Support for Hibernate types in Jackson.
16 | */
17 | @Bean
18 | public Hibernate5Module hibernate5Module() {
19 | return new Hibernate5Module();
20 | }
21 |
22 | /*
23 | * Jackson Afterburner module to speed up serialization/deserialization.
24 | */
25 | @Bean
26 | public AfterburnerModule afterburnerModule() {
27 | return new AfterburnerModule();
28 | }
29 |
30 | /*
31 | * Module for serialization/deserialization of RFC7807 Problem.
32 | */
33 | @Bean
34 | ProblemModule problemModule() {
35 | return new ProblemModule();
36 | }
37 |
38 | /*
39 | * Module for serialization/deserialization of ConstraintViolationProblem.
40 | */
41 | @Bean
42 | ConstraintViolationProblemModule constraintViolationProblemModule() {
43 | return new ConstraintViolationProblemModule();
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/config/LocaleConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.config;
2 |
3 | import io.github.jhipster.config.locale.AngularCookieLocaleResolver;
4 |
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.springframework.web.servlet.LocaleResolver;
8 | import org.springframework.web.servlet.config.annotation.*;
9 | import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
10 |
11 | @Configuration
12 | public class LocaleConfiguration implements WebMvcConfigurer {
13 |
14 | @Bean(name = "localeResolver")
15 | public LocaleResolver localeResolver() {
16 | AngularCookieLocaleResolver cookieLocaleResolver = new AngularCookieLocaleResolver();
17 | cookieLocaleResolver.setCookieName("NG_TRANSLATE_LANG_KEY");
18 | return cookieLocaleResolver;
19 | }
20 |
21 | @Override
22 | public void addInterceptors(InterceptorRegistry registry) {
23 | LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
24 | localeChangeInterceptor.setParamName("language");
25 | registry.addInterceptor(localeChangeInterceptor);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/config/LoggingAspectConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.config;
2 |
3 | import com.okta.developer.aop.logging.LoggingAspect;
4 |
5 | import io.github.jhipster.config.JHipsterConstants;
6 |
7 | import org.springframework.context.annotation.*;
8 | import org.springframework.core.env.Environment;
9 |
10 | @Configuration
11 | @EnableAspectJAutoProxy
12 | public class LoggingAspectConfiguration {
13 |
14 | @Bean
15 | @Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)
16 | public LoggingAspect loggingAspect(Environment env) {
17 | return new LoggingAspect(env);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/config/audit/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Audit specific code.
3 | */
4 | package com.okta.developer.config.audit;
5 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/config/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Spring Framework configuration files.
3 | */
4 | package com.okta.developer.config;
5 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/domain/AbstractAuditingEntity.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.domain;
2 |
3 | import java.io.Serializable;
4 |
5 | import com.fasterxml.jackson.annotation.JsonIgnore;
6 | import org.hibernate.envers.Audited;
7 | import org.springframework.data.annotation.CreatedBy;
8 | import org.springframework.data.annotation.CreatedDate;
9 | import org.springframework.data.annotation.LastModifiedBy;
10 | import org.springframework.data.annotation.LastModifiedDate;
11 | import org.springframework.data.jpa.domain.support.AuditingEntityListener;
12 | import java.time.Instant;
13 | import javax.persistence.Column;
14 | import javax.persistence.EntityListeners;
15 | import javax.persistence.MappedSuperclass;
16 |
17 | /**
18 | * Base abstract class for entities which will hold definitions for created, last modified by and created,
19 | * last modified by date.
20 | */
21 | @MappedSuperclass
22 | @Audited
23 | @EntityListeners(AuditingEntityListener.class)
24 | public abstract class AbstractAuditingEntity implements Serializable {
25 |
26 | private static final long serialVersionUID = 1L;
27 |
28 | @CreatedBy
29 | @Column(name = "created_by", nullable = false, length = 50, updatable = false)
30 | @JsonIgnore
31 | private String createdBy;
32 |
33 | @CreatedDate
34 | @Column(name = "created_date", nullable = false, updatable = false)
35 | @JsonIgnore
36 | private Instant createdDate = Instant.now();
37 |
38 | @LastModifiedBy
39 | @Column(name = "last_modified_by", length = 50)
40 | @JsonIgnore
41 | private String lastModifiedBy;
42 |
43 | @LastModifiedDate
44 | @Column(name = "last_modified_date")
45 | @JsonIgnore
46 | private Instant lastModifiedDate = Instant.now();
47 |
48 | public String getCreatedBy() {
49 | return createdBy;
50 | }
51 |
52 | public void setCreatedBy(String createdBy) {
53 | this.createdBy = createdBy;
54 | }
55 |
56 | public Instant getCreatedDate() {
57 | return createdDate;
58 | }
59 |
60 | public void setCreatedDate(Instant createdDate) {
61 | this.createdDate = createdDate;
62 | }
63 |
64 | public String getLastModifiedBy() {
65 | return lastModifiedBy;
66 | }
67 |
68 | public void setLastModifiedBy(String lastModifiedBy) {
69 | this.lastModifiedBy = lastModifiedBy;
70 | }
71 |
72 | public Instant getLastModifiedDate() {
73 | return lastModifiedDate;
74 | }
75 |
76 | public void setLastModifiedDate(Instant lastModifiedDate) {
77 | this.lastModifiedDate = lastModifiedDate;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/domain/Authority.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.domain;
2 |
3 | import org.hibernate.annotations.Cache;
4 | import org.hibernate.annotations.CacheConcurrencyStrategy;
5 | import javax.persistence.Entity;
6 | import javax.persistence.Id;
7 | import javax.persistence.Table;
8 | import javax.persistence.Column;
9 | import javax.validation.constraints.NotNull;
10 | import javax.validation.constraints.Size;
11 | import java.io.Serializable;
12 |
13 | /**
14 | * An authority (a security role) used by Spring Security.
15 | */
16 | @Entity
17 | @Table(name = "jhi_authority")
18 | @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
19 | public class Authority implements Serializable {
20 |
21 | private static final long serialVersionUID = 1L;
22 |
23 | @NotNull
24 | @Size(max = 50)
25 | @Id
26 | @Column(length = 50)
27 | private String name;
28 |
29 | public String getName() {
30 | return name;
31 | }
32 |
33 | public void setName(String name) {
34 | this.name = name;
35 | }
36 |
37 | @Override
38 | public boolean equals(Object o) {
39 | if (this == o) {
40 | return true;
41 | }
42 | if (o == null || getClass() != o.getClass()) {
43 | return false;
44 | }
45 |
46 | Authority authority = (Authority) o;
47 |
48 | return !(name != null ? !name.equals(authority.name) : authority.name != null);
49 | }
50 |
51 | @Override
52 | public int hashCode() {
53 | return name != null ? name.hashCode() : 0;
54 | }
55 |
56 | @Override
57 | public String toString() {
58 | return "Authority{" +
59 | "name='" + name + '\'' +
60 | "}";
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/domain/PersistentAuditEvent.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.domain;
2 |
3 | import javax.persistence.*;
4 | import javax.validation.constraints.NotNull;
5 | import java.io.Serializable;
6 | import java.time.Instant;
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | /**
11 | * Persist AuditEvent managed by the Spring Boot actuator.
12 | *
13 | * @see org.springframework.boot.actuate.audit.AuditEvent
14 | */
15 | @Entity
16 | @Table(name = "jhi_persistent_audit_event")
17 | public class PersistentAuditEvent implements Serializable {
18 |
19 | private static final long serialVersionUID = 1L;
20 |
21 | @Id
22 | @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
23 | @SequenceGenerator(name = "sequenceGenerator")
24 | @Column(name = "event_id")
25 | private Long id;
26 |
27 | @NotNull
28 | @Column(nullable = false)
29 | private String principal;
30 |
31 | @Column(name = "event_date")
32 | private Instant auditEventDate;
33 |
34 | @Column(name = "event_type")
35 | private String auditEventType;
36 |
37 | @ElementCollection
38 | @MapKeyColumn(name = "name")
39 | @Column(name = "value")
40 | @CollectionTable(name = "jhi_persistent_audit_evt_data", joinColumns=@JoinColumn(name="event_id"))
41 | private Map data = new HashMap<>();
42 |
43 | public Long getId() {
44 | return id;
45 | }
46 |
47 | public void setId(Long id) {
48 | this.id = id;
49 | }
50 |
51 | public String getPrincipal() {
52 | return principal;
53 | }
54 |
55 | public void setPrincipal(String principal) {
56 | this.principal = principal;
57 | }
58 |
59 | public Instant getAuditEventDate() {
60 | return auditEventDate;
61 | }
62 |
63 | public void setAuditEventDate(Instant auditEventDate) {
64 | this.auditEventDate = auditEventDate;
65 | }
66 |
67 | public String getAuditEventType() {
68 | return auditEventType;
69 | }
70 |
71 | public void setAuditEventType(String auditEventType) {
72 | this.auditEventType = auditEventType;
73 | }
74 |
75 | public Map getData() {
76 | return data;
77 | }
78 |
79 | public void setData(Map data) {
80 | this.data = data;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/domain/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * JPA domain objects.
3 | */
4 | package com.okta.developer.domain;
5 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/repository/AlbumRepository.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.repository;
2 |
3 | import com.okta.developer.domain.Album;
4 | import org.springframework.data.jpa.repository.*;
5 | import org.springframework.stereotype.Repository;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * Spring Data repository for the Album entity.
11 | */
12 | @SuppressWarnings("unused")
13 | @Repository
14 | public interface AlbumRepository extends JpaRepository {
15 |
16 | @Query("select album from Album album where album.user.login = ?#{principal.username}")
17 | List findByUserIsCurrentUser();
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/repository/AuthorityRepository.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.repository;
2 |
3 | import com.okta.developer.domain.Authority;
4 |
5 | import org.springframework.data.jpa.repository.JpaRepository;
6 |
7 | /**
8 | * Spring Data JPA repository for the Authority entity.
9 | */
10 | public interface AuthorityRepository extends JpaRepository {
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/repository/PersistenceAuditEventRepository.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.repository;
2 |
3 | import com.okta.developer.domain.PersistentAuditEvent;
4 | import org.springframework.data.domain.Page;
5 | import org.springframework.data.domain.Pageable;
6 | import org.springframework.data.jpa.repository.JpaRepository;
7 |
8 | import java.time.Instant;
9 | import java.util.List;
10 |
11 | /**
12 | * Spring Data JPA repository for the PersistentAuditEvent entity.
13 | */
14 | public interface PersistenceAuditEventRepository extends JpaRepository {
15 |
16 | List findByPrincipal(String principal);
17 |
18 | List findByAuditEventDateAfter(Instant after);
19 |
20 | List findByPrincipalAndAuditEventDateAfter(String principal, Instant after);
21 |
22 | List findByPrincipalAndAuditEventDateAfterAndAuditEventType(String principle, Instant after, String type);
23 |
24 | Page findAllByAuditEventDateBetween(Instant fromDate, Instant toDate, Pageable pageable);
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/repository/PhotoRepository.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.repository;
2 |
3 | import com.okta.developer.domain.Photo;
4 | import org.springframework.data.domain.Page;
5 | import org.springframework.data.domain.Pageable;
6 | import org.springframework.data.jpa.repository.*;
7 | import org.springframework.data.repository.query.Param;
8 | import org.springframework.stereotype.Repository;
9 |
10 | import java.util.List;
11 | import java.util.Optional;
12 |
13 | /**
14 | * Spring Data repository for the Photo entity.
15 | */
16 | @SuppressWarnings("unused")
17 | @Repository
18 | public interface PhotoRepository extends JpaRepository {
19 |
20 | @Query(value = "select distinct photo from Photo photo left join fetch photo.tags",
21 | countQuery = "select count(distinct photo) from Photo photo")
22 | Page findAllWithEagerRelationships(Pageable pageable);
23 |
24 | @Query(value = "select distinct photo from Photo photo left join fetch photo.tags")
25 | List findAllWithEagerRelationships();
26 |
27 | @Query("select photo from Photo photo left join fetch photo.tags where photo.id =:id")
28 | Optional findOneWithEagerRelationships(@Param("id") Long id);
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/repository/TagRepository.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.repository;
2 |
3 | import com.okta.developer.domain.Tag;
4 | import org.springframework.data.jpa.repository.*;
5 | import org.springframework.stereotype.Repository;
6 |
7 |
8 | /**
9 | * Spring Data repository for the Tag entity.
10 | */
11 | @SuppressWarnings("unused")
12 | @Repository
13 | public interface TagRepository extends JpaRepository {
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/repository/UserRepository.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.repository;
2 |
3 | import com.okta.developer.domain.User;
4 |
5 | import org.springframework.cache.annotation.Cacheable;
6 | import org.springframework.data.domain.Page;
7 | import org.springframework.data.domain.Pageable;
8 | import org.springframework.data.jpa.repository.EntityGraph;
9 | import org.springframework.data.jpa.repository.JpaRepository;
10 | import org.springframework.stereotype.Repository;
11 | import java.util.List;
12 | import java.util.Optional;
13 | import java.time.Instant;
14 |
15 | /**
16 | * Spring Data JPA repository for the User entity.
17 | */
18 | @Repository
19 | public interface UserRepository extends JpaRepository {
20 |
21 | String USERS_BY_LOGIN_CACHE = "usersByLogin";
22 |
23 | String USERS_BY_EMAIL_CACHE = "usersByEmail";
24 |
25 | List findAllByActivatedIsFalseAndCreatedDateBefore(Instant dateTime);
26 |
27 | Optional findOneByEmailIgnoreCase(String email);
28 |
29 | Optional findOneByLogin(String login);
30 |
31 | @EntityGraph(attributePaths = "authorities")
32 | Optional findOneWithAuthoritiesById(Long id);
33 |
34 | @EntityGraph(attributePaths = "authorities")
35 | @Cacheable(cacheNames = USERS_BY_LOGIN_CACHE)
36 | Optional findOneWithAuthoritiesByLogin(String login);
37 |
38 | @EntityGraph(attributePaths = "authorities")
39 | @Cacheable(cacheNames = USERS_BY_EMAIL_CACHE)
40 | Optional findOneWithAuthoritiesByEmail(String email);
41 |
42 | Page findAllByLoginNot(Pageable pageable, String login);
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/repository/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Spring Data JPA repositories.
3 | */
4 | package com.okta.developer.repository;
5 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/security/AuthoritiesConstants.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.security;
2 |
3 | /**
4 | * Constants for Spring Security authorities.
5 | */
6 | public final class AuthoritiesConstants {
7 |
8 | public static final String ADMIN = "ROLE_ADMIN";
9 |
10 | public static final String USER = "ROLE_USER";
11 |
12 | public static final String ANONYMOUS = "ROLE_ANONYMOUS";
13 |
14 | private AuthoritiesConstants() {
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/security/SpringSecurityAuditorAware.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.security;
2 |
3 | import com.okta.developer.config.Constants;
4 |
5 | import java.util.Optional;
6 |
7 | import org.springframework.data.domain.AuditorAware;
8 | import org.springframework.stereotype.Component;
9 |
10 | /**
11 | * Implementation of AuditorAware based on Spring Security.
12 | */
13 | @Component
14 | public class SpringSecurityAuditorAware implements AuditorAware {
15 |
16 | @Override
17 | public Optional getCurrentAuditor() {
18 | return Optional.of(SecurityUtils.getCurrentUserLogin().orElse(Constants.SYSTEM_ACCOUNT));
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/security/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Spring Security configuration.
3 | */
4 | package com.okta.developer.security;
5 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/service/AuditEventService.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.service;
2 |
3 | import com.okta.developer.config.audit.AuditEventConverter;
4 | import com.okta.developer.repository.PersistenceAuditEventRepository;
5 | import org.springframework.boot.actuate.audit.AuditEvent;
6 | import org.springframework.data.domain.Page;
7 | import org.springframework.data.domain.Pageable;
8 | import org.springframework.stereotype.Service;
9 | import org.springframework.transaction.annotation.Transactional;
10 |
11 | import java.time.Instant;
12 | import java.util.Optional;
13 |
14 | /**
15 | * Service for managing audit events.
16 | *
17 | * This is the default implementation to support SpringBoot Actuator AuditEventRepository
18 | */
19 | @Service
20 | @Transactional
21 | public class AuditEventService {
22 |
23 | private final PersistenceAuditEventRepository persistenceAuditEventRepository;
24 |
25 | private final AuditEventConverter auditEventConverter;
26 |
27 | public AuditEventService(
28 | PersistenceAuditEventRepository persistenceAuditEventRepository,
29 | AuditEventConverter auditEventConverter) {
30 |
31 | this.persistenceAuditEventRepository = persistenceAuditEventRepository;
32 | this.auditEventConverter = auditEventConverter;
33 | }
34 |
35 | public Page findAll(Pageable pageable) {
36 | return persistenceAuditEventRepository.findAll(pageable)
37 | .map(auditEventConverter::convertToAuditEvent);
38 | }
39 |
40 | public Page findByDates(Instant fromDate, Instant toDate, Pageable pageable) {
41 | return persistenceAuditEventRepository.findAllByAuditEventDateBetween(fromDate, toDate, pageable)
42 | .map(auditEventConverter::convertToAuditEvent);
43 | }
44 |
45 | public Optional find(Long id) {
46 | return Optional.ofNullable(persistenceAuditEventRepository.findById(id))
47 | .filter(Optional::isPresent)
48 | .map(Optional::get)
49 | .map(auditEventConverter::convertToAuditEvent);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/service/dto/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Data Transfer Objects.
3 | */
4 | package com.okta.developer.service.dto;
5 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/service/mapper/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * MapStruct mappers for mapping domain objects and Data Transfer Objects.
3 | */
4 | package com.okta.developer.service.mapper;
5 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/service/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Service layer beans.
3 | */
4 | package com.okta.developer.service;
5 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/web/rest/LogsResource.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.web.rest;
2 |
3 | import com.okta.developer.web.rest.vm.LoggerVM;
4 |
5 | import ch.qos.logback.classic.Level;
6 | import ch.qos.logback.classic.LoggerContext;
7 | import com.codahale.metrics.annotation.Timed;
8 | import org.slf4j.LoggerFactory;
9 | import org.springframework.http.HttpStatus;
10 | import org.springframework.web.bind.annotation.*;
11 |
12 | import java.util.List;
13 | import java.util.stream.Collectors;
14 |
15 | /**
16 | * Controller for view and managing Log Level at runtime.
17 | */
18 | @RestController
19 | @RequestMapping("/management")
20 | public class LogsResource {
21 |
22 | @GetMapping("/logs")
23 | @Timed
24 | public List getList() {
25 | LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
26 | return context.getLoggerList()
27 | .stream()
28 | .map(LoggerVM::new)
29 | .collect(Collectors.toList());
30 | }
31 |
32 | @PutMapping("/logs")
33 | @ResponseStatus(HttpStatus.NO_CONTENT)
34 | @Timed
35 | public void changeLevel(@RequestBody LoggerVM jsonLogger) {
36 | LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
37 | context.getLogger(jsonLogger.getName()).setLevel(Level.valueOf(jsonLogger.getLevel()));
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/web/rest/errors/BadRequestAlertException.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.web.rest.errors;
2 |
3 | import org.zalando.problem.AbstractThrowableProblem;
4 | import org.zalando.problem.Status;
5 |
6 | import java.net.URI;
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | public class BadRequestAlertException extends AbstractThrowableProblem {
11 |
12 | private static final long serialVersionUID = 1L;
13 |
14 | private final String entityName;
15 |
16 | private final String errorKey;
17 |
18 | public BadRequestAlertException(String defaultMessage, String entityName, String errorKey) {
19 | this(ErrorConstants.DEFAULT_TYPE, defaultMessage, entityName, errorKey);
20 | }
21 |
22 | public BadRequestAlertException(URI type, String defaultMessage, String entityName, String errorKey) {
23 | super(type, defaultMessage, Status.BAD_REQUEST, null, null, null, getAlertParameters(entityName, errorKey));
24 | this.entityName = entityName;
25 | this.errorKey = errorKey;
26 | }
27 |
28 | public String getEntityName() {
29 | return entityName;
30 | }
31 |
32 | public String getErrorKey() {
33 | return errorKey;
34 | }
35 |
36 | private static Map getAlertParameters(String entityName, String errorKey) {
37 | Map parameters = new HashMap<>();
38 | parameters.put("message", "error." + errorKey);
39 | parameters.put("params", entityName);
40 | return parameters;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/web/rest/errors/CustomParameterizedException.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.web.rest.errors;
2 |
3 | import org.zalando.problem.AbstractThrowableProblem;
4 |
5 | import java.util.HashMap;
6 | import java.util.Map;
7 |
8 | import static org.zalando.problem.Status.BAD_REQUEST;
9 |
10 | /**
11 | * Custom, parameterized exception, which can be translated on the client side.
12 | * For example:
13 | *
14 | *
15 | * throw new CustomParameterizedException("myCustomError", "hello", "world");
16 | *
17 | *
18 | * Can be translated with:
19 | *
20 | *
21 | * "error.myCustomError" : "The server says {{param0}} to {{param1}}"
22 | *
23 | */
24 | public class CustomParameterizedException extends AbstractThrowableProblem {
25 |
26 | private static final long serialVersionUID = 1L;
27 |
28 | private static final String PARAM = "param";
29 |
30 | public CustomParameterizedException(String message, String... params) {
31 | this(message, toParamMap(params));
32 | }
33 |
34 | public CustomParameterizedException(String message, Map paramMap) {
35 | super(ErrorConstants.PARAMETERIZED_TYPE, "Parameterized Exception", BAD_REQUEST, null, null, null, toProblemParameters(message, paramMap));
36 | }
37 |
38 | public static Map toParamMap(String... params) {
39 | Map paramMap = new HashMap<>();
40 | if (params != null && params.length > 0) {
41 | for (int i = 0; i < params.length; i++) {
42 | paramMap.put(PARAM + i, params[i]);
43 | }
44 | }
45 | return paramMap;
46 | }
47 |
48 | public static Map toProblemParameters(String message, Map paramMap) {
49 | Map parameters = new HashMap<>();
50 | parameters.put("message", message);
51 | parameters.put("params", paramMap);
52 | return parameters;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/web/rest/errors/EmailAlreadyUsedException.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.web.rest.errors;
2 |
3 | public class EmailAlreadyUsedException extends BadRequestAlertException {
4 |
5 | private static final long serialVersionUID = 1L;
6 |
7 | public EmailAlreadyUsedException() {
8 | super(ErrorConstants.EMAIL_ALREADY_USED_TYPE, "Email is already in use!", "userManagement", "emailexists");
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/web/rest/errors/EmailNotFoundException.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.web.rest.errors;
2 |
3 | import org.zalando.problem.AbstractThrowableProblem;
4 | import org.zalando.problem.Status;
5 |
6 | public class EmailNotFoundException extends AbstractThrowableProblem {
7 |
8 | private static final long serialVersionUID = 1L;
9 |
10 | public EmailNotFoundException() {
11 | super(ErrorConstants.EMAIL_NOT_FOUND_TYPE, "Email address not registered", Status.BAD_REQUEST);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/web/rest/errors/ErrorConstants.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.web.rest.errors;
2 |
3 | import java.net.URI;
4 |
5 | public final class ErrorConstants {
6 |
7 | public static final String ERR_CONCURRENCY_FAILURE = "error.concurrencyFailure";
8 | public static final String ERR_VALIDATION = "error.validation";
9 | public static final String PROBLEM_BASE_URL = "https://www.jhipster.tech/problem";
10 | public static final URI DEFAULT_TYPE = URI.create(PROBLEM_BASE_URL + "/problem-with-message");
11 | public static final URI CONSTRAINT_VIOLATION_TYPE = URI.create(PROBLEM_BASE_URL + "/constraint-violation");
12 | public static final URI PARAMETERIZED_TYPE = URI.create(PROBLEM_BASE_URL + "/parameterized");
13 | public static final URI ENTITY_NOT_FOUND_TYPE = URI.create(PROBLEM_BASE_URL + "/entity-not-found");
14 | public static final URI INVALID_PASSWORD_TYPE = URI.create(PROBLEM_BASE_URL + "/invalid-password");
15 | public static final URI EMAIL_ALREADY_USED_TYPE = URI.create(PROBLEM_BASE_URL + "/email-already-used");
16 | public static final URI LOGIN_ALREADY_USED_TYPE = URI.create(PROBLEM_BASE_URL + "/login-already-used");
17 | public static final URI EMAIL_NOT_FOUND_TYPE = URI.create(PROBLEM_BASE_URL + "/email-not-found");
18 |
19 | private ErrorConstants() {
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/web/rest/errors/FieldErrorVM.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.web.rest.errors;
2 |
3 | import java.io.Serializable;
4 |
5 | public class FieldErrorVM implements Serializable {
6 |
7 | private static final long serialVersionUID = 1L;
8 |
9 | private final String objectName;
10 |
11 | private final String field;
12 |
13 | private final String message;
14 |
15 | public FieldErrorVM(String dto, String field, String message) {
16 | this.objectName = dto;
17 | this.field = field;
18 | this.message = message;
19 | }
20 |
21 | public String getObjectName() {
22 | return objectName;
23 | }
24 |
25 | public String getField() {
26 | return field;
27 | }
28 |
29 | public String getMessage() {
30 | return message;
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/web/rest/errors/InternalServerErrorException.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.web.rest.errors;
2 |
3 | import org.zalando.problem.AbstractThrowableProblem;
4 | import org.zalando.problem.Status;
5 |
6 | /**
7 | * Simple exception with a message, that returns an Internal Server Error code.
8 | */
9 | public class InternalServerErrorException extends AbstractThrowableProblem {
10 |
11 | private static final long serialVersionUID = 1L;
12 |
13 | public InternalServerErrorException(String message) {
14 | super(ErrorConstants.DEFAULT_TYPE, message, Status.INTERNAL_SERVER_ERROR);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/web/rest/errors/InvalidPasswordException.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.web.rest.errors;
2 |
3 | import org.zalando.problem.AbstractThrowableProblem;
4 | import org.zalando.problem.Status;
5 |
6 | public class InvalidPasswordException extends AbstractThrowableProblem {
7 |
8 | private static final long serialVersionUID = 1L;
9 |
10 | public InvalidPasswordException() {
11 | super(ErrorConstants.INVALID_PASSWORD_TYPE, "Incorrect password", Status.BAD_REQUEST);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/web/rest/errors/LoginAlreadyUsedException.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.web.rest.errors;
2 |
3 | public class LoginAlreadyUsedException extends BadRequestAlertException {
4 |
5 | private static final long serialVersionUID = 1L;
6 |
7 | public LoginAlreadyUsedException() {
8 | super(ErrorConstants.LOGIN_ALREADY_USED_TYPE, "Login name already used!", "userManagement", "userexists");
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/web/rest/errors/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Specific errors used with Zalando's "problem-spring-web" library.
3 | *
4 | * More information on https://github.com/zalando/problem-spring-web
5 | */
6 | package com.okta.developer.web.rest.errors;
7 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/web/rest/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Spring MVC REST controllers.
3 | */
4 | package com.okta.developer.web.rest;
5 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/web/rest/util/HeaderUtil.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.web.rest.util;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.http.HttpHeaders;
6 |
7 | /**
8 | * Utility class for HTTP headers creation.
9 | */
10 | public final class HeaderUtil {
11 |
12 | private static final Logger log = LoggerFactory.getLogger(HeaderUtil.class);
13 |
14 | private static final String APPLICATION_NAME = "galleryApp";
15 |
16 | private HeaderUtil() {
17 | }
18 |
19 | public static HttpHeaders createAlert(String message, String param) {
20 | HttpHeaders headers = new HttpHeaders();
21 | headers.add("X-galleryApp-alert", message);
22 | headers.add("X-galleryApp-params", param);
23 | return headers;
24 | }
25 |
26 | public static HttpHeaders createEntityCreationAlert(String entityName, String param) {
27 | return createAlert(APPLICATION_NAME + "." + entityName + ".created", param);
28 | }
29 |
30 | public static HttpHeaders createEntityUpdateAlert(String entityName, String param) {
31 | return createAlert(APPLICATION_NAME + "." + entityName + ".updated", param);
32 | }
33 |
34 | public static HttpHeaders createEntityDeletionAlert(String entityName, String param) {
35 | return createAlert(APPLICATION_NAME + "." + entityName + ".deleted", param);
36 | }
37 |
38 | public static HttpHeaders createFailureAlert(String entityName, String errorKey, String defaultMessage) {
39 | log.error("Entity processing failed, {}", defaultMessage);
40 | HttpHeaders headers = new HttpHeaders();
41 | headers.add("X-galleryApp-error", "error." + errorKey);
42 | headers.add("X-galleryApp-params", entityName);
43 | return headers;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/web/rest/util/PaginationUtil.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.web.rest.util;
2 |
3 | import org.springframework.data.domain.Page;
4 | import org.springframework.http.HttpHeaders;
5 | import org.springframework.web.util.UriComponentsBuilder;
6 |
7 | /**
8 | * Utility class for handling pagination.
9 | *
10 | *
11 | * Pagination uses the same principles as the GitHub API,
12 | * and follow RFC 5988 (Link header).
13 | */
14 | public final class PaginationUtil {
15 |
16 | private PaginationUtil() {
17 | }
18 |
19 | public static HttpHeaders generatePaginationHttpHeaders(Page page, String baseUrl) {
20 |
21 | HttpHeaders headers = new HttpHeaders();
22 | headers.add("X-Total-Count", Long.toString(page.getTotalElements()));
23 | String link = "";
24 | if ((page.getNumber() + 1) < page.getTotalPages()) {
25 | link = "<" + generateUri(baseUrl, page.getNumber() + 1, page.getSize()) + ">; rel=\"next\",";
26 | }
27 | // prev link
28 | if ((page.getNumber()) > 0) {
29 | link += "<" + generateUri(baseUrl, page.getNumber() - 1, page.getSize()) + ">; rel=\"prev\",";
30 | }
31 | // last and first link
32 | int lastPage = 0;
33 | if (page.getTotalPages() > 0) {
34 | lastPage = page.getTotalPages() - 1;
35 | }
36 | link += "<" + generateUri(baseUrl, lastPage, page.getSize()) + ">; rel=\"last\",";
37 | link += "<" + generateUri(baseUrl, 0, page.getSize()) + ">; rel=\"first\"";
38 | headers.add(HttpHeaders.LINK, link);
39 | return headers;
40 | }
41 |
42 | private static String generateUri(String baseUrl, int page, int size) {
43 | return UriComponentsBuilder.fromUriString(baseUrl).queryParam("page", page).queryParam("size", size).toUriString();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/web/rest/vm/LoggerVM.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.web.rest.vm;
2 |
3 | import ch.qos.logback.classic.Logger;
4 |
5 | /**
6 | * View Model object for storing a Logback logger.
7 | */
8 | public class LoggerVM {
9 |
10 | private String name;
11 |
12 | private String level;
13 |
14 | public LoggerVM(Logger logger) {
15 | this.name = logger.getName();
16 | this.level = logger.getEffectiveLevel().toString();
17 | }
18 |
19 | public LoggerVM() {
20 | // Empty public constructor used by Jackson.
21 | }
22 |
23 | public String getName() {
24 | return name;
25 | }
26 |
27 | public void setName(String name) {
28 | this.name = name;
29 | }
30 |
31 | public String getLevel() {
32 | return level;
33 | }
34 |
35 | public void setLevel(String level) {
36 | this.level = level;
37 | }
38 |
39 | @Override
40 | public String toString() {
41 | return "LoggerVM{" +
42 | "name='" + name + '\'' +
43 | ", level='" + level + '\'' +
44 | '}';
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/web/rest/vm/ManagedUserVM.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.web.rest.vm;
2 |
3 | import com.okta.developer.service.dto.UserDTO;
4 |
5 | /**
6 | * View Model extending the UserDTO, which is meant to be used in the user management UI.
7 | */
8 | public class ManagedUserVM extends UserDTO {
9 |
10 | public ManagedUserVM() {
11 | // Empty constructor needed for Jackson.
12 | }
13 |
14 | @Override
15 | public String toString() {
16 | return "ManagedUserVM{" +
17 | "} " + super.toString();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/okta/developer/web/rest/vm/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * View Models used by Spring MVC REST controllers.
3 | */
4 | package com.okta.developer.web.rest.vm;
5 |
--------------------------------------------------------------------------------
/src/main/resources/.h2.server.properties:
--------------------------------------------------------------------------------
1 | #H2 Server Properties
2 | 0=JHipster H2 (Disk)|org.h2.Driver|jdbc\:h2\:file\:./target/h2db/db/gallery|gallery
3 | webAllowOthers=true
4 | webPort=8082
5 | webSSL=false
6 |
--------------------------------------------------------------------------------
/src/main/resources/banner.txt:
--------------------------------------------------------------------------------
1 |
2 | ${AnsiColor.GREEN} ██╗${AnsiColor.BLUE} ██╗ ██╗ ████████╗ ███████╗ ██████╗ ████████╗ ████████╗ ███████╗
3 | ${AnsiColor.GREEN} ██║${AnsiColor.BLUE} ██║ ██║ ╚══██╔══╝ ██╔═══██╗ ██╔════╝ ╚══██╔══╝ ██╔═════╝ ██╔═══██╗
4 | ${AnsiColor.GREEN} ██║${AnsiColor.BLUE} ████████║ ██║ ███████╔╝ ╚█████╗ ██║ ██████╗ ███████╔╝
5 | ${AnsiColor.GREEN}██╗ ██║${AnsiColor.BLUE} ██╔═══██║ ██║ ██╔════╝ ╚═══██╗ ██║ ██╔═══╝ ██╔══██║
6 | ${AnsiColor.GREEN}╚██████╔╝${AnsiColor.BLUE} ██║ ██║ ████████╗ ██║ ██████╔╝ ██║ ████████╗ ██║ ╚██╗
7 | ${AnsiColor.GREEN} ╚═════╝ ${AnsiColor.BLUE} ╚═╝ ╚═╝ ╚═══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══════╝ ╚═╝ ╚═╝
8 |
9 | ${AnsiColor.BRIGHT_BLUE}:: JHipster 🤓 :: Running Spring Boot ${spring-boot.version} ::
10 | :: https://www.jhipster.tech ::${AnsiColor.DEFAULT}
11 |
--------------------------------------------------------------------------------
/src/main/resources/config/application-heroku.yml:
--------------------------------------------------------------------------------
1 | # ===================================================================
2 | # Spring Boot configuration for the "heroku" profile.
3 | #
4 | # This configuration overrides the application.yml file.
5 | # ===================================================================
6 |
7 | # ===================================================================
8 | # Standard Spring Boot properties.
9 | # Full reference is available at:
10 | # http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
11 | # ===================================================================
12 |
13 | eureka:
14 | instance:
15 | hostname: gallery-pwa.herokuapp.com
16 | non-secure-port: 80
17 | prefer-ip-address: false
18 | client:
19 | service-url:
20 | defaultZone: ${JHIPSTER_REGISTRY_URL}/eureka/
21 |
22 | spring:
23 | datasource:
24 | type: com.zaxxer.hikari.HikariDataSource
25 | url: ${JDBC_DATABASE_URL}
26 | username: ${JDBC_DATABASE_USERNAME}
27 | password: ${JDBC_DATABASE_PASSWORD}
28 | hikari:
29 | maximumPoolSize: 8
30 |
--------------------------------------------------------------------------------
/src/main/resources/config/bootstrap-heroku.yml:
--------------------------------------------------------------------------------
1 | # ===================================================================
2 | # Spring Cloud Config bootstrap configuration for the "heroku" profile
3 | # ===================================================================
4 |
5 | spring:
6 | cloud:
7 | config:
8 | fail-fast: true
9 | uri: ${JHIPSTER_REGISTRY_URL}/config
10 |
--------------------------------------------------------------------------------
/src/main/resources/config/liquibase/authorities.csv:
--------------------------------------------------------------------------------
1 | name
2 | ROLE_ADMIN
3 | ROLE_USER
4 |
--------------------------------------------------------------------------------
/src/main/resources/config/liquibase/changelog/20180625042224_added_entity_Album.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/main/resources/config/liquibase/changelog/20180625042224_added_entity_constraints_Album.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
9 |
10 |
11 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/main/resources/config/liquibase/changelog/20180625042225_added_entity_constraints_Photo.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
9 |
10 |
11 |
16 |
17 |
22 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/main/resources/config/liquibase/changelog/20180625042226_added_entity_Tag.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/main/resources/config/liquibase/master.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/main/resources/config/liquibase/users.csv:
--------------------------------------------------------------------------------
1 | id;login;first_name;last_name;email;image_url;activated;lang_key;created_by;last_modified_by
2 | 1;system;System;System;system@localhost;;true;en;system;system
3 | 2;anonymoususer;Anonymous;User;anonymous@localhost;;true;en;system;system
4 |
--------------------------------------------------------------------------------
/src/main/resources/config/liquibase/users_authorities.csv:
--------------------------------------------------------------------------------
1 | user_id;authority_name
2 | 1;ROLE_ADMIN
3 | 1;ROLE_USER
4 | 3;ROLE_ADMIN
5 | 3;ROLE_USER
6 | 4;ROLE_USER
7 |
--------------------------------------------------------------------------------
/src/main/resources/i18n/messages.properties:
--------------------------------------------------------------------------------
1 | # Error page
2 | error.title=Your request cannot be processed
3 | error.subtitle=Sorry, an error has occurred.
4 | error.status=Status:
5 | error.message=Message:
6 |
7 | # Activation email
8 | email.activation.title=gallery account activation
9 | email.activation.greeting=Dear {0}
10 | email.activation.text1=Your gallery account has been created, please click on the URL below to activate it:
11 | email.activation.text2=Regards,
12 | email.signature=gallery Team.
13 |
14 | # Creation email
15 | email.creation.text1=Your gallery account has been created, please click on the URL below to access it:
16 |
17 | # Reset email
18 | email.reset.title=gallery password reset
19 | email.reset.greeting=Dear {0}
20 | email.reset.text1=For your gallery account a password reset was requested, please click on the URL below to reset it:
21 | email.reset.text2=Regards,
22 |
--------------------------------------------------------------------------------
/src/main/resources/i18n/messages_en.properties:
--------------------------------------------------------------------------------
1 | # Error page
2 | error.title=Your request cannot be processed
3 | error.subtitle=Sorry, an error has occurred.
4 | error.status=Status:
5 | error.message=Message:
6 |
7 | # Activation email
8 | email.activation.title=gallery account activation
9 | email.activation.greeting=Dear {0}
10 | email.activation.text1=Your gallery account has been created, please click on the URL below to activate it:
11 | email.activation.text2=Regards,
12 | email.signature=gallery Team.
13 |
14 | # Creation email
15 | email.creation.text1=Your gallery account has been created, please click on the URL below to access it:
16 |
17 | # Reset email
18 | email.reset.title=gallery password reset
19 | email.reset.greeting=Dear {0}
20 | email.reset.text1=For your gallery account a password reset was requested, please click on the URL below to reset it:
21 | email.reset.text2=Regards,
22 |
--------------------------------------------------------------------------------
/src/main/resources/i18n/messages_fr.properties:
--------------------------------------------------------------------------------
1 | # Error page
2 | error.title=Votre demande ne peut être traitée
3 | error.subtitle=Désolé, une erreur s'est produite.
4 | error.status=Statut :
5 | error.message=Message :
6 |
7 | # Activation email
8 | email.activation.title=Activation de votre compte gallery
9 | email.activation.greeting=Cher {0}
10 | email.activation.text1=Votre compte gallery a été créé, pour l'activer merci de cliquer sur le lien ci-dessous :
11 | email.activation.text2=Cordialement,
12 | email.signature=gallery.
13 |
14 | # Creation email
15 | email.creation.text1=Votre compte gallery a été créé, merci de cliquer sur le lien ci-dessous pour y accéder :
16 |
17 | # Reset email
18 | email.reset.title=gallery Réinitialisation de mot de passe
19 | email.reset.greeting=Cher {0}
20 | email.reset.text1=Un nouveau mot de passe pour votre compte gallery a été demandé, veuillez cliquer sur le lien ci-dessous pour le réinitialiser :
21 | email.reset.text2=Cordialement,
22 |
--------------------------------------------------------------------------------
/src/main/webapp/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Page Not Found
6 |
7 |
8 |
55 |
56 |
57 | Page Not Found
58 | Sorry, but the page you were trying to view does not exist.
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/src/main/webapp/app/config/axios-interceptor.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { getBasePath, Storage } from 'react-jhipster';
3 |
4 | const TIMEOUT = 1000000; // 10000
5 | const setupAxiosInterceptors = onUnauthenticated => {
6 | const onRequestSuccess = config => {
7 | const token = Storage.local.get('jhi-authenticationToken') || Storage.session.get('jhi-authenticationToken');
8 | if (token) {
9 | config.headers.Authorization = `Bearer ${token}`;
10 | }
11 | config.timeout = TIMEOUT;
12 | config.url = `${getBasePath().replace(/\/$/, '')}${config.url}`;
13 | return config;
14 | };
15 | const onResponseSuccess = response => response;
16 | const onResponseError = err => {
17 | const status = err.status || err.response.status;
18 | if (status === 403 || status === 401) {
19 | onUnauthenticated();
20 | }
21 | return Promise.reject(err);
22 | };
23 | axios.interceptors.request.use(onRequestSuccess);
24 | axios.interceptors.response.use(onResponseSuccess, onResponseError);
25 | };
26 |
27 | export default setupAxiosInterceptors;
28 |
--------------------------------------------------------------------------------
/src/main/webapp/app/config/constants.ts:
--------------------------------------------------------------------------------
1 | const config = {
2 | VERSION: process.env.VERSION,
3 | SERVER_API_URL: process.env.SERVER_API_URL
4 | };
5 |
6 | export default config;
7 |
8 | export const SERVER_API_URL = '';
9 |
10 | export const AUTHORITIES = {
11 | ADMIN: 'ROLE_ADMIN',
12 | USER: 'ROLE_USER'
13 | };
14 |
15 | export const messages = {
16 | DATA_ERROR_ALERT: 'Internal Error'
17 | };
18 |
19 | export const APP_DATE_FORMAT = 'DD/MM/YY HH:mm';
20 | export const APP_TIMESTAMP_FORMAT = 'DD/MM/YY HH:mm:ss';
21 | export const APP_LOCAL_DATE_FORMAT = 'DD/MM/YYYY';
22 | export const APP_LOCAL_DATETIME_FORMAT = 'YYYY-MM-DDThh:mm';
23 | export const APP_WHOLE_NUMBER_FORMAT = '0,0';
24 | export const APP_TWO_DIGITS_AFTER_POINT_NUMBER_FORMAT = '0,0.[00]';
25 |
--------------------------------------------------------------------------------
/src/main/webapp/app/config/devtools.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { createDevTools } from 'redux-devtools';
3 | import LogMonitor from 'redux-devtools-log-monitor';
4 | import DockMonitor from 'redux-devtools-dock-monitor';
5 | // You can toggle visibility of devTools with ctrl + H
6 | // and change their position with ctrl + Q
7 | export default createDevTools(
8 |
9 |
10 |
11 | );
12 |
--------------------------------------------------------------------------------
/src/main/webapp/app/config/error-middleware.ts:
--------------------------------------------------------------------------------
1 | import { isPromise } from 'react-jhipster';
2 |
3 | const getErrorMessage = errorData => {
4 | let message = errorData.message;
5 | if (errorData.fieldErrors) {
6 | errorData.fieldErrors.forEach(fErr => {
7 | message += `\nfield: ${fErr.field}, Object: ${fErr.objectName}, message: ${fErr.message}\n`;
8 | });
9 | }
10 | return message;
11 | };
12 |
13 | export default () => next => action => {
14 | // If not a promise, continue on
15 | if (!isPromise(action.payload)) {
16 | return next(action);
17 | }
18 |
19 | /**
20 | *
21 | * The error middleware serves to dispatch the initial pending promise to
22 | * the promise middleware, but adds a `catch`.
23 | * It need not run in production
24 | */
25 | if (process.env.NODE_ENV === 'development') {
26 | // Dispatch initial pending promise, but catch any errors
27 | return next(action).catch(error => {
28 | console.error(`${action.type} caught at middleware with reason: ${JSON.stringify(error.message)}.`);
29 | if (error && error.response && error.response.data) {
30 | const message = getErrorMessage(error.response.data);
31 | console.error(`Actual cause: ${message}`);
32 | }
33 |
34 | return Promise.reject(error);
35 | });
36 | }
37 | return next(action);
38 | };
39 |
--------------------------------------------------------------------------------
/src/main/webapp/app/config/icon-loader.ts:
--------------------------------------------------------------------------------
1 | import {
2 | faSort,
3 | faEye,
4 | faSync,
5 | faBan,
6 | faTrash,
7 | faArrowLeft,
8 | faSave,
9 | faPlus,
10 | faPencilAlt,
11 | faUser,
12 | faTachometerAlt,
13 | faHeart,
14 | faList,
15 | faTasks,
16 | faBook,
17 | faHdd,
18 | faClock,
19 | faSignInAlt,
20 | faSignOutAlt,
21 | faWrench,
22 | faThList,
23 | faUserPlus,
24 | faAsterisk,
25 | faFlag,
26 | faBell,
27 | faHome,
28 | faTimesCircle,
29 | faSearch
30 | } from '@fortawesome/fontawesome-free-solid';
31 | import fontawesome from '@fortawesome/fontawesome';
32 |
33 | export const loadIcons = () => {
34 | fontawesome.library.add(
35 | faSort,
36 | faEye,
37 | faSync,
38 | faBan,
39 | faTrash,
40 | faArrowLeft,
41 | faSave,
42 | faPlus,
43 | faPencilAlt,
44 | faUser,
45 | faTachometerAlt,
46 | faHeart,
47 | faList,
48 | faTasks,
49 | faBook,
50 | faHdd,
51 | faClock,
52 | faSignInAlt,
53 | faSignOutAlt,
54 | faWrench,
55 | faThList,
56 | faUserPlus,
57 | faAsterisk,
58 | faFlag,
59 | faBell,
60 | faHome
61 | );
62 | };
63 |
--------------------------------------------------------------------------------
/src/main/webapp/app/config/logger-middleware.ts:
--------------------------------------------------------------------------------
1 | export default () => next => action => {
2 | if (process.env.NODE_ENV !== 'production') {
3 | const { type, payload, meta } = action;
4 |
5 | console.groupCollapsed(type);
6 | // tslint:disable-next-line
7 | console.log('Payload:', payload);
8 | // tslint:disable-next-line
9 | console.log('Meta:', meta);
10 | console.groupEnd();
11 | }
12 |
13 | return next(action);
14 | };
15 |
--------------------------------------------------------------------------------
/src/main/webapp/app/config/store.ts:
--------------------------------------------------------------------------------
1 | import { createStore, applyMiddleware, compose, GenericStoreEnhancer } from 'redux';
2 | import promiseMiddleware from 'redux-promise-middleware';
3 | import thunkMiddleware from 'redux-thunk';
4 | import reducer, { IRootState } from 'app/shared/reducers';
5 | import DevTools from './devtools';
6 | import errorMiddleware from './error-middleware';
7 | import notificationMiddleware from './notification-middleware';
8 | import loggerMiddleware from './logger-middleware';
9 | import { loadingBarMiddleware } from 'react-redux-loading-bar';
10 |
11 | const defaultMiddlewares = [
12 | thunkMiddleware,
13 | errorMiddleware,
14 | notificationMiddleware,
15 | promiseMiddleware(),
16 | loadingBarMiddleware(),
17 | loggerMiddleware
18 | ];
19 | const composedMiddlewares = middlewares =>
20 | process.env.NODE_ENV === 'development'
21 | ? (compose(applyMiddleware(...defaultMiddlewares, ...middlewares), DevTools.instrument()) as GenericStoreEnhancer)
22 | : compose(applyMiddleware(...defaultMiddlewares, ...middlewares));
23 |
24 | const initialize = (initialState?: IRootState, middlewares = []) => createStore(reducer, initialState, composedMiddlewares(middlewares));
25 |
26 | export default initialize;
27 |
--------------------------------------------------------------------------------
/src/main/webapp/app/config/translation.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { TranslatorContext, Storage } from 'react-jhipster';
3 |
4 | import { setLocale } from 'app/shared/reducers/locale';
5 |
6 | export const locales = ['en', 'fr'];
7 |
8 | let currentLocale;
9 | const savedLocale = Storage.session.get('locale', 'en');
10 | TranslatorContext.setDefaultLocale('en');
11 | TranslatorContext.setRenderInnerTextForMissingKeys(false);
12 |
13 | export const registerLocales = store => {
14 | locales.forEach(locale => {
15 | axios.get(`/i18n/${locale}.json`).then(response => {
16 | TranslatorContext.registerTranslations(locale, response.data);
17 | });
18 | });
19 | store.subscribe(() => {
20 | const previousLocale = currentLocale;
21 | currentLocale = store.getState().locale.currentLocale;
22 | if (previousLocale !== currentLocale) {
23 | Storage.session.set('locale', currentLocale);
24 | TranslatorContext.setLocale(currentLocale);
25 | }
26 | });
27 | store.dispatch(setLocale(savedLocale));
28 | };
29 |
--------------------------------------------------------------------------------
/src/main/webapp/app/entities/album/album-delete-dialog.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { connect } from 'react-redux';
3 | import { RouteComponentProps } from 'react-router-dom';
4 | import { Modal, ModalHeader, ModalBody, ModalFooter, Button } from 'reactstrap';
5 | import { Translate, ICrudGetAction, ICrudDeleteAction } from 'react-jhipster';
6 | import FontAwesomeIcon from '@fortawesome/react-fontawesome';
7 |
8 | import { IAlbum } from 'app/shared/model/album.model';
9 | import { IRootState } from 'app/shared/reducers';
10 | import { getEntity, deleteEntity } from './album.reducer';
11 |
12 | export interface IAlbumDeleteDialogProps extends StateProps, DispatchProps, RouteComponentProps<{ id: number }> {}
13 |
14 | export class AlbumDeleteDialog extends React.Component {
15 | componentDidMount() {
16 | this.props.getEntity(this.props.match.params.id);
17 | }
18 |
19 | confirmDelete = event => {
20 | this.props.deleteEntity(this.props.albumEntity.id);
21 | this.handleClose(event);
22 | };
23 |
24 | handleClose = event => {
25 | event.stopPropagation();
26 | this.props.history.goBack();
27 | };
28 |
29 | render() {
30 | const { albumEntity } = this.props;
31 | return (
32 |
33 |
34 | Confirm delete operation
35 |
36 |
37 |
38 | Are you sure you want to delete this Album?
39 |
40 |
41 |
42 |
46 |
50 |
51 |
52 | );
53 | }
54 | }
55 |
56 | const mapStateToProps = ({ album }: IRootState) => ({
57 | albumEntity: album.entity
58 | });
59 |
60 | const mapDispatchToProps = { getEntity, deleteEntity };
61 |
62 | type StateProps = ReturnType;
63 | type DispatchProps = typeof mapDispatchToProps;
64 |
65 | export default connect(mapStateToProps, mapDispatchToProps)(AlbumDeleteDialog);
66 |
--------------------------------------------------------------------------------
/src/main/webapp/app/entities/album/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Switch } from 'react-router-dom';
3 |
4 | import ErrorBoundaryRoute from 'app/shared/error/error-boundary-route';
5 |
6 | import Album from './album';
7 | import AlbumDetail from './album-detail';
8 | import AlbumUpdate from './album-update';
9 | import AlbumDeleteDialog from './album-delete-dialog';
10 |
11 | const Routes = ({ match }) => (
12 | <>
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | >
21 | );
22 |
23 | export default Routes;
24 |
--------------------------------------------------------------------------------
/src/main/webapp/app/entities/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Switch } from 'react-router-dom';
3 |
4 | // tslint:disable-next-line:no-unused-variable
5 | import ErrorBoundaryRoute from 'app/shared/error/error-boundary-route';
6 |
7 | import Album from './album';
8 | import Photo from './photo';
9 | import Tag from './tag';
10 | /* jhipster-needle-add-route-import - JHipster will add routes here */
11 |
12 | const Routes = ({ match }) => (
13 |
14 |
15 | {/* prettier-ignore */}
16 |
17 |
18 |
19 | {/* jhipster-needle-add-route-path - JHipster will routes here */}
20 |
21 |
22 | );
23 |
24 | export default Routes;
25 |
--------------------------------------------------------------------------------
/src/main/webapp/app/entities/photo/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Switch } from 'react-router-dom';
3 |
4 | import ErrorBoundaryRoute from 'app/shared/error/error-boundary-route';
5 |
6 | import Photo from './photo';
7 | import PhotoDetail from './photo-detail';
8 | import PhotoUpdate from './photo-update';
9 | import PhotoDeleteDialog from './photo-delete-dialog';
10 |
11 | const Routes = ({ match }) => (
12 | <>
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | >
21 | );
22 |
23 | export default Routes;
24 |
--------------------------------------------------------------------------------
/src/main/webapp/app/entities/photo/photo-delete-dialog.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { connect } from 'react-redux';
3 | import { RouteComponentProps } from 'react-router-dom';
4 | import { Modal, ModalHeader, ModalBody, ModalFooter, Button } from 'reactstrap';
5 | import { Translate, ICrudGetAction, ICrudDeleteAction } from 'react-jhipster';
6 | import FontAwesomeIcon from '@fortawesome/react-fontawesome';
7 |
8 | import { IPhoto } from 'app/shared/model/photo.model';
9 | import { IRootState } from 'app/shared/reducers';
10 | import { getEntity, deleteEntity } from './photo.reducer';
11 |
12 | export interface IPhotoDeleteDialogProps extends StateProps, DispatchProps, RouteComponentProps<{ id: number }> {}
13 |
14 | export class PhotoDeleteDialog extends React.Component {
15 | componentDidMount() {
16 | this.props.getEntity(this.props.match.params.id);
17 | }
18 |
19 | confirmDelete = event => {
20 | this.props.deleteEntity(this.props.photoEntity.id);
21 | this.handleClose(event);
22 | };
23 |
24 | handleClose = event => {
25 | event.stopPropagation();
26 | this.props.history.goBack();
27 | };
28 |
29 | render() {
30 | const { photoEntity } = this.props;
31 | return (
32 |
33 |
34 | Confirm delete operation
35 |
36 |
37 |
38 | Are you sure you want to delete this Photo?
39 |
40 |
41 |
42 |
46 |
50 |
51 |
52 | );
53 | }
54 | }
55 |
56 | const mapStateToProps = ({ photo }: IRootState) => ({
57 | photoEntity: photo.entity
58 | });
59 |
60 | const mapDispatchToProps = { getEntity, deleteEntity };
61 |
62 | type StateProps = ReturnType;
63 | type DispatchProps = typeof mapDispatchToProps;
64 |
65 | export default connect(mapStateToProps, mapDispatchToProps)(PhotoDeleteDialog);
66 |
--------------------------------------------------------------------------------
/src/main/webapp/app/entities/tag/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Switch } from 'react-router-dom';
3 |
4 | import ErrorBoundaryRoute from 'app/shared/error/error-boundary-route';
5 |
6 | import Tag from './tag';
7 | import TagDetail from './tag-detail';
8 | import TagUpdate from './tag-update';
9 | import TagDeleteDialog from './tag-delete-dialog';
10 |
11 | const Routes = ({ match }) => (
12 | <>
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | >
21 | );
22 |
23 | export default Routes;
24 |
--------------------------------------------------------------------------------
/src/main/webapp/app/entities/tag/tag-delete-dialog.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { connect } from 'react-redux';
3 | import { RouteComponentProps } from 'react-router-dom';
4 | import { Modal, ModalHeader, ModalBody, ModalFooter, Button } from 'reactstrap';
5 | import { Translate, ICrudGetAction, ICrudDeleteAction } from 'react-jhipster';
6 | import FontAwesomeIcon from '@fortawesome/react-fontawesome';
7 |
8 | import { ITag } from 'app/shared/model/tag.model';
9 | import { IRootState } from 'app/shared/reducers';
10 | import { getEntity, deleteEntity } from './tag.reducer';
11 |
12 | export interface ITagDeleteDialogProps extends StateProps, DispatchProps, RouteComponentProps<{ id: number }> {}
13 |
14 | export class TagDeleteDialog extends React.Component {
15 | componentDidMount() {
16 | this.props.getEntity(this.props.match.params.id);
17 | }
18 |
19 | confirmDelete = event => {
20 | this.props.deleteEntity(this.props.tagEntity.id);
21 | this.handleClose(event);
22 | };
23 |
24 | handleClose = event => {
25 | event.stopPropagation();
26 | this.props.history.goBack();
27 | };
28 |
29 | render() {
30 | const { tagEntity } = this.props;
31 | return (
32 |
33 |
34 | Confirm delete operation
35 |
36 |
37 |
38 | Are you sure you want to delete this Tag?
39 |
40 |
41 |
42 |
46 |
50 |
51 |
52 | );
53 | }
54 | }
55 |
56 | const mapStateToProps = ({ tag }: IRootState) => ({
57 | tagEntity: tag.entity
58 | });
59 |
60 | const mapDispatchToProps = { getEntity, deleteEntity };
61 |
62 | type StateProps = ReturnType;
63 | type DispatchProps = typeof mapDispatchToProps;
64 |
65 | export default connect(mapStateToProps, mapDispatchToProps)(TagDeleteDialog);
66 |
--------------------------------------------------------------------------------
/src/main/webapp/app/entities/tag/tag-detail.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { connect } from 'react-redux';
3 | import { Link, RouteComponentProps } from 'react-router-dom';
4 | import { Button, Row, Col } from 'reactstrap';
5 | // tslint:disable-next-line:no-unused-variable
6 | import { Translate, ICrudGetAction } from 'react-jhipster';
7 | import FontAwesomeIcon from '@fortawesome/react-fontawesome';
8 |
9 | import { IRootState } from 'app/shared/reducers';
10 | import { getEntity } from './tag.reducer';
11 | import { ITag } from 'app/shared/model/tag.model';
12 | // tslint:disable-next-line:no-unused-variable
13 | import { APP_DATE_FORMAT, APP_LOCAL_DATE_FORMAT } from 'app/config/constants';
14 |
15 | export interface ITagDetailProps extends StateProps, DispatchProps, RouteComponentProps<{ id: number }> {}
16 |
17 | export class TagDetail extends React.Component {
18 | componentDidMount() {
19 | this.props.getEntity(this.props.match.params.id);
20 | }
21 |
22 | render() {
23 | const { tagEntity } = this.props;
24 | return (
25 |
26 |
27 |
28 | Tag [{tagEntity.id}]
29 |
30 |
31 | -
32 |
33 | Name
34 |
35 |
36 | - {tagEntity.name}
37 |
38 |
44 |
50 |
51 |
52 | );
53 | }
54 | }
55 |
56 | const mapStateToProps = ({ tag }: IRootState) => ({
57 | tagEntity: tag.entity
58 | });
59 |
60 | const mapDispatchToProps = { getEntity };
61 |
62 | type StateProps = ReturnType;
63 | type DispatchProps = typeof mapDispatchToProps;
64 |
65 | export default connect(mapStateToProps, mapDispatchToProps)(TagDetail);
66 |
--------------------------------------------------------------------------------
/src/main/webapp/app/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as ReactDOM from 'react-dom';
3 | import { Provider } from 'react-redux';
4 | import { bindActionCreators } from 'redux';
5 | import { AppContainer } from 'react-hot-loader';
6 |
7 | import DevTools from './config/devtools';
8 | import initStore from './config/store';
9 | import { registerLocales } from './config/translation';
10 | import setupAxiosInterceptors from './config/axios-interceptor';
11 | import { clearAuthentication } from './shared/reducers/authentication';
12 | import ErrorBoundary from './shared/error/error-boundary';
13 | import AppComponent from './app';
14 | import { loadIcons } from './config/icon-loader';
15 |
16 | const devTools = process.env.NODE_ENV === 'development' ? : null;
17 |
18 | const store = initStore();
19 | registerLocales(store);
20 |
21 | const actions = bindActionCreators({ clearAuthentication }, store.dispatch);
22 | setupAxiosInterceptors(() => actions.clearAuthentication('login.error.unauthorized'));
23 |
24 | loadIcons();
25 |
26 | const rootEl = document.getElementById('root');
27 |
28 | const render = Component =>
29 | ReactDOM.render(
30 |
31 |
32 |
33 |
34 | {/* If this slows down the app in dev disable it and enable when required */}
35 | {devTools}
36 |
37 |
38 |
39 |
40 | ,
41 | rootEl
42 | );
43 |
44 | render(AppComponent);
45 |
46 | // This is quite unstable
47 | // if (module.hot) {
48 | // module.hot.accept('./app', () => {
49 | // const NextApp = require<{ default: typeof AppComponent }>('./app').default;
50 | // render(NextApp);
51 | // });
52 | // }
53 |
--------------------------------------------------------------------------------
/src/main/webapp/app/modules/administration/docs/docs.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | const DocsPage = () => (
4 |
5 |
6 |
7 | );
8 |
9 | export default DocsPage;
10 |
--------------------------------------------------------------------------------
/src/main/webapp/app/modules/administration/health/health-modal.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Table, Modal, ModalHeader, ModalBody, ModalFooter, Button } from 'reactstrap';
3 |
4 | const formatDiskSpaceOutput = rawValue => {
5 | // Should display storage space in an human readable unit
6 | const val = rawValue / 1073741824;
7 | if (val > 1) {
8 | // Value
9 | return val.toFixed(2) + ' GB';
10 | } else {
11 | return (rawValue / 1048576).toFixed(2) + ' MB';
12 | }
13 | };
14 |
15 | const HealthModal = ({ handleClose, healthObject, showModal }) => {
16 | const data = healthObject.details || {};
17 | return (
18 |
19 | {healthObject.name}
20 |
21 |
22 |
23 |
24 | | Name |
25 | Value |
26 |
27 |
28 |
29 | {Object.keys(data).map((key, index) => (
30 |
31 | | {key} |
32 | {healthObject.name === 'diskSpace' ? formatDiskSpaceOutput(data[key]) : JSON.stringify(data[key])} |
33 |
34 | ))}
35 |
36 |
37 |
38 |
39 |
42 |
43 |
44 | );
45 | };
46 |
47 | export default HealthModal;
48 |
--------------------------------------------------------------------------------
/src/main/webapp/app/modules/administration/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import ErrorBoundaryRoute from 'app/shared/error/error-boundary-route';
4 | import Logs from './logs/logs';
5 | import Health from './health/health';
6 | import Metrics from './metrics/metrics';
7 | import Configuration from './configuration/configuration';
8 | import Audits from './audits/audits';
9 | import Docs from './docs/docs';
10 |
11 | const Routes = ({ match }) => (
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | );
21 |
22 | export default Routes;
23 |
--------------------------------------------------------------------------------
/src/main/webapp/app/modules/administration/metrics/thread-item.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Collapse, Card, CardBody, Row } from 'reactstrap';
3 |
4 | export interface IThreadItemProps {
5 | threadDumpInfo: any;
6 | }
7 |
8 | export interface IThreadItemState {
9 | collapse: boolean;
10 | }
11 |
12 | export class ThreadItem extends React.Component {
13 | state: IThreadItemState = {
14 | collapse: false
15 | };
16 |
17 | toggleStackTrace = () => {
18 | this.setState({
19 | collapse: !this.state.collapse
20 | });
21 | };
22 |
23 | render() {
24 | const { threadDumpInfo } = this.props;
25 |
26 | return (
27 |
49 | );
50 | }
51 | }
52 |
53 | export default ThreadItem;
54 |
--------------------------------------------------------------------------------
/src/main/webapp/app/modules/home/home.css:
--------------------------------------------------------------------------------
1 | /* ==========================================================================
2 | Main page styles
3 | ========================================================================== */
4 | .hipster {
5 | display: inline-block;
6 | width: 347px;
7 | height: 497px;
8 | background: url('../../../static/images/logo-jhipster-react.svg') no-repeat center top;
9 | background-size: contain;
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/webapp/app/modules/login/logout.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { connect } from 'react-redux';
3 | import { Redirect } from 'react-router-dom';
4 |
5 | import { IRootState } from 'app/shared/reducers';
6 | import { logout } from 'app/shared/reducers/authentication';
7 |
8 | export interface ILogoutProps extends StateProps, DispatchProps {}
9 |
10 | export class Logout extends React.Component {
11 | componentDidMount() {
12 | this.props.logout();
13 | }
14 |
15 | render() {
16 | return (
17 |
18 |
Logged out successfully!
19 |
24 |
25 | );
26 | }
27 | }
28 |
29 | const mapStateToProps = (storeState: IRootState) => ({});
30 |
31 | const mapDispatchToProps = { logout };
32 |
33 | type StateProps = ReturnType;
34 | type DispatchProps = typeof mapDispatchToProps;
35 |
36 | export default connect(mapStateToProps, mapDispatchToProps)(Logout);
37 |
--------------------------------------------------------------------------------
/src/main/webapp/app/routes.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Switch } from 'react-router-dom';
3 |
4 | import Logout from 'app/modules/login/logout';
5 | import Home from 'app/modules/home/home';
6 | import Admin from 'app/modules/administration';
7 | import Entities from 'app/entities';
8 | import PrivateRoute from 'app/shared/auth/private-route';
9 | import ErrorBoundaryRoute from 'app/shared/error/error-boundary-route';
10 | import { AUTHORITIES } from 'app/config/constants';
11 |
12 | const Routes = () => (
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | );
22 |
23 | export default Routes;
24 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/error/error-boundary-route.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Route, RouteProps } from 'react-router-dom';
3 | import ErrorBoundary from 'app/shared/error/error-boundary';
4 |
5 | export const ErrorBoundaryRoute = ({ component: Component, ...rest }: RouteProps) => {
6 | const encloseInErrorBoundary = props => (
7 |
8 |
9 |
10 | );
11 |
12 | if (!Component) throw new Error(`A component needs to be specified for path ${(rest as any).path}`);
13 |
14 | return ;
15 | };
16 |
17 | export default ErrorBoundaryRoute;
18 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/error/error-boundary.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | interface IErrorBoundaryProps {
4 | readonly children: JSX.Element | JSX.Element[];
5 | }
6 |
7 | interface IErrorBoundaryState {
8 | readonly error: any;
9 | readonly errorInfo: any;
10 | }
11 |
12 | class ErrorBoundary extends React.Component {
13 | readonly state: IErrorBoundaryState = { error: undefined, errorInfo: undefined };
14 |
15 | componentDidCatch(error, errorInfo) {
16 | this.setState({
17 | error,
18 | errorInfo
19 | });
20 | }
21 |
22 | render() {
23 | const { error, errorInfo } = this.state;
24 | if (errorInfo) {
25 | const errorDetails =
26 | process.env.NODE_ENV === 'development' ? (
27 |
28 | {error && error.toString()}
29 |
30 | {errorInfo.componentStack}
31 |
32 | ) : (
33 | undefined
34 | );
35 | return (
36 |
37 |
An unexpected error has occurred.
38 | {errorDetails}
39 |
40 | );
41 | }
42 | return this.props.children;
43 | }
44 | }
45 |
46 | export default ErrorBoundary;
47 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/layout/footer/footer.css:
--------------------------------------------------------------------------------
1 | .footer {
2 | height: 50px;
3 | }
4 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/layout/footer/footer.tsx:
--------------------------------------------------------------------------------
1 | import './footer.css';
2 |
3 | import * as React from 'react';
4 | import { Translate } from 'react-jhipster';
5 | import { Col, Row } from 'reactstrap';
6 |
7 | const Footer = props => (
8 |
9 |
10 |
11 |
12 | Your footer
13 |
14 |
15 |
16 |
17 | );
18 |
19 | export default Footer;
20 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/layout/header/header-components.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Translate } from 'react-jhipster';
3 |
4 | import { UncontrolledDropdown, DropdownToggle, DropdownMenu, NavItem, NavLink, NavbarBrand } from 'reactstrap';
5 | import { NavLink as Link } from 'react-router-dom';
6 | import FontAwesomeIcon from '@fortawesome/react-fontawesome';
7 |
8 | import appConfig from 'app/config/constants';
9 |
10 | export const NavDropdown = props => (
11 |
12 |
13 |
14 | {props.name}
15 |
16 |
17 | {props.children}
18 |
19 |
20 | );
21 |
22 | export const BrandIcon = props => (
23 |
24 |

25 |
26 | );
27 |
28 | export const Brand = props => (
29 |
30 |
31 |
32 | Gallery
33 |
34 | {appConfig.VERSION}
35 |
36 | );
37 |
38 | export const Home = props => (
39 |
40 |
41 |
42 | Home
43 |
44 |
45 | );
46 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/layout/header/menus/account.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { DropdownItem } from 'reactstrap';
3 | import FontAwesomeIcon from '@fortawesome/react-fontawesome';
4 | import { NavLink as Link } from 'react-router-dom';
5 | import { getLoginUrl } from 'app/shared/util/url-utils';
6 | import { NavDropdown } from '../header-components';
7 |
8 | const accountMenuItemsAuthenticated = (
9 | <>
10 |
11 | Logout
12 |
13 | >
14 | );
15 |
16 | const accountMenuItems = (
17 | <>
18 |
19 | Login
20 |
21 | >
22 | );
23 |
24 | export const AccountMenu = ({ isAuthenticated = false }) => (
25 |
28 | );
29 |
30 | export default AccountMenu;
31 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/layout/header/menus/admin.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { DropdownItem } from 'reactstrap';
3 | import FontAwesomeIcon from '@fortawesome/react-fontawesome';
4 | import { NavLink as Link } from 'react-router-dom';
5 | import { NavDropdown } from '../header-components';
6 |
7 | const adminMenuItems = (
8 | <>
9 |
10 | Metrics
11 |
12 |
13 | Health
14 |
15 |
16 | Configuration
17 |
18 |
19 | Audits
20 |
21 | {/* jhipster-needle-add-element-to-admin-menu - JHipster will add entities to the admin menu here */}
22 |
23 | Logs
24 |
25 | >
26 | );
27 |
28 | const swaggerItem = (
29 |
30 | API Docs
31 |
32 | );
33 |
34 | const databaseItem = (
35 |
36 | Database
37 |
38 | );
39 |
40 | export const AdminMenu = ({ showSwagger, showDatabase }) => (
41 |
47 | );
48 |
49 | export default AdminMenu;
50 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/layout/header/menus/entities.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { DropdownItem } from 'reactstrap';
3 | import FontAwesomeIcon from '@fortawesome/react-fontawesome';
4 | import { NavLink as Link } from 'react-router-dom';
5 | import { NavDropdown } from '../header-components';
6 |
7 | export const EntitiesMenu = props => (
8 | // tslint:disable-next-line:jsx-self-close
9 |
21 | );
22 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/layout/header/menus/index.ts:
--------------------------------------------------------------------------------
1 | export * from './account';
2 | export * from './admin';
3 | export * from './locale';
4 | export * from './entities';
5 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/layout/header/menus/locale.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { DropdownItem } from 'reactstrap';
3 | import { NavDropdown } from '../header-components';
4 | import { locales } from 'app/config/translation';
5 |
6 | export const LocaleMenu = ({ currentLocale, onClick }) =>
7 | locales.length > 1 && (
8 |
9 | {locales.map(lang => (
10 |
11 | {lang.toUpperCase()}
12 |
13 | ))}
14 |
15 | );
16 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/layout/password/password-strength-bar.css:
--------------------------------------------------------------------------------
1 | /* ==========================================================================
2 | start Password strength bar style
3 | ========================================================================== */
4 | ul#strengthBar {
5 | display: inline;
6 | list-style: none;
7 | margin: 0;
8 | margin-left: 15px;
9 | padding: 0;
10 | vertical-align: 2px;
11 | }
12 |
13 | .point:last {
14 | margin: 0 !important;
15 | }
16 | .point {
17 | background: #ddd;
18 | border-radius: 2px;
19 | display: inline-block;
20 | height: 5px;
21 | margin-right: 1px;
22 | width: 20px;
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/layout/password/password-strength-bar.tsx:
--------------------------------------------------------------------------------
1 | import './password-strength-bar.css';
2 |
3 | import * as React from 'react';
4 | import { Translate } from 'react-jhipster';
5 |
6 | export interface IPasswordStrengthBarProps {
7 | password: string;
8 | }
9 |
10 | export const PasswordStrengthBar = ({ password }: IPasswordStrengthBarProps) => {
11 | const colors = ['#F00', '#F90', '#FF0', '#9F0', '#0F0'];
12 |
13 | const measureStrength = (p: string): number => {
14 | let force = 0;
15 | const regex = /[$-/:-?{-~!"^_`\[\]]/g;
16 | const flags = {
17 | lowerLetters: /[a-z]+/.test(p),
18 | upperLetters: /[A-Z]+/.test(p),
19 | numbers: /[0-9]+/.test(p),
20 | symbols: regex.test(p)
21 | };
22 |
23 | const passedMatches = Object.values(flags).filter((isMatchedFlag: boolean) => !!isMatchedFlag).length;
24 |
25 | force += 2 * p.length + (p.length >= 10 ? 1 : 0);
26 | force += passedMatches * 10;
27 |
28 | // penality (short password)
29 | force = p.length <= 6 ? Math.min(force, 10) : force;
30 |
31 | // penality (poor variety of characters)
32 | force = passedMatches === 1 ? Math.min(force, 10) : force;
33 | force = passedMatches === 2 ? Math.min(force, 20) : force;
34 | force = passedMatches === 3 ? Math.min(force, 40) : force;
35 |
36 | return force;
37 | };
38 |
39 | const getColor = (s: number): any => {
40 | let idx = 0;
41 | if (s <= 10) {
42 | idx = 0;
43 | } else if (s <= 20) {
44 | idx = 1;
45 | } else if (s <= 30) {
46 | idx = 2;
47 | } else if (s <= 40) {
48 | idx = 3;
49 | } else {
50 | idx = 4;
51 | }
52 | return { idx: idx + 1, col: colors[idx] };
53 | };
54 |
55 | const getPoints = force => {
56 | const pts = [];
57 | for (let i = 0; i < 5; i++) {
58 | pts.push();
59 | }
60 | return pts;
61 | };
62 |
63 | const strength = getColor(measureStrength(password));
64 | const points = getPoints(strength);
65 |
66 | return (
67 |
68 |
69 | Password strength:
70 |
71 |
72 |
73 | );
74 | };
75 |
76 | export default PasswordStrengthBar;
77 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/model/album.model.ts:
--------------------------------------------------------------------------------
1 | import { Moment } from 'moment';
2 | import { IUser } from './user.model';
3 |
4 | export interface IAlbum {
5 | id?: number;
6 | title?: string;
7 | description?: any;
8 | created?: Moment;
9 | user?: IUser;
10 | }
11 |
12 | export const defaultValue: Readonly = {};
13 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/model/photo.model.ts:
--------------------------------------------------------------------------------
1 | import { Moment } from 'moment';
2 | import { IAlbum } from './album.model';
3 | import { ITag } from './tag.model';
4 |
5 | export interface IPhoto {
6 | id?: number;
7 | title?: string;
8 | description?: any;
9 | imageContentType?: string;
10 | image?: any;
11 | height?: number;
12 | width?: number;
13 | taken?: Moment;
14 | uploaded?: Moment;
15 | album?: IAlbum;
16 | tags?: ITag[];
17 | }
18 |
19 | export const defaultValue: Readonly = {};
20 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/model/tag.model.ts:
--------------------------------------------------------------------------------
1 | import { IPhoto } from './photo.model';
2 |
3 | export interface ITag {
4 | id?: number;
5 | name?: string;
6 | photos?: IPhoto[];
7 | }
8 |
9 | export const defaultValue: Readonly = {};
10 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/model/user.model.ts:
--------------------------------------------------------------------------------
1 | export interface IUser {
2 | id?: any;
3 | login?: string;
4 | firstName?: string;
5 | lastName?: string;
6 | email?: string;
7 | activated?: boolean;
8 | langKey?: string;
9 | authorities?: any[];
10 | createdBy?: string;
11 | createdDate?: Date;
12 | lastModifiedBy?: string;
13 | lastModifiedDate?: Date;
14 | password?: string;
15 | }
16 |
17 | export const defaultValue: Readonly = {
18 | id: null,
19 | login: null,
20 | firstName: null,
21 | lastName: null,
22 | email: null,
23 | activated: false,
24 | langKey: null,
25 | authorities: null,
26 | createdBy: null,
27 | createdDate: null,
28 | lastModifiedBy: null,
29 | lastModifiedDate: null,
30 | password: null
31 | };
32 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/reducers/action-type.util.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Appends REQUEST asyc action type
3 | */
4 |
5 | export const REQUEST = actionType => `${actionType}_PENDING`;
6 |
7 | /**
8 | * Appends SUCCESS asyc action type
9 | */
10 |
11 | export const SUCCESS = actionType => `${actionType}_FULFILLED`;
12 |
13 | /**
14 | * Appends FAILURE asyc action type
15 | */
16 |
17 | export const FAILURE = actionType => `${actionType}_REJECTED`;
18 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/reducers/application-profile.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 |
3 | import { SUCCESS } from 'app/shared/reducers/action-type.util';
4 |
5 | export const ACTION_TYPES = {
6 | GET_PROFILE: 'applicationProfile/GET_PROFILE'
7 | };
8 |
9 | const initialState = {
10 | ribbonEnv: '',
11 | inProduction: true,
12 | isSwaggerEnabled: false
13 | };
14 |
15 | export type ApplicationProfileState = Readonly;
16 |
17 | export default (state: ApplicationProfileState = initialState, action): ApplicationProfileState => {
18 | switch (action.type) {
19 | case SUCCESS(ACTION_TYPES.GET_PROFILE):
20 | const { data } = action.payload;
21 | return {
22 | ...state,
23 | ribbonEnv: data['display-ribbon-on-profiles'],
24 | inProduction: data.activeProfiles.includes('prod'),
25 | isSwaggerEnabled: data.activeProfiles.includes('swagger')
26 | };
27 | default:
28 | return state;
29 | }
30 | };
31 |
32 | export const getProfile = () => ({
33 | type: ACTION_TYPES.GET_PROFILE,
34 | payload: axios.get('/management/info')
35 | });
36 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/reducers/authentication.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 |
3 | import { REQUEST, SUCCESS, FAILURE } from 'app/shared/reducers/action-type.util';
4 |
5 | export const ACTION_TYPES = {
6 | GET_SESSION: 'authentication/GET_SESSION',
7 | LOGOUT: 'authentication/LOGOUT',
8 | CLEAR_AUTH: 'authentication/CLEAR_AUTH',
9 | ERROR_MESSAGE: 'authentication/ERROR_MESSAGE'
10 | };
11 |
12 | const initialState = {
13 | loading: false,
14 | isAuthenticated: false,
15 | account: {} as any,
16 | errorMessage: null as string, // Errors returned from server side
17 | redirectMessage: null as string
18 | };
19 |
20 | export type AuthenticationState = Readonly;
21 |
22 | // Reducer
23 |
24 | export default (state: AuthenticationState = initialState, action): AuthenticationState => {
25 | switch (action.type) {
26 | case REQUEST(ACTION_TYPES.GET_SESSION):
27 | return {
28 | ...state,
29 | loading: true
30 | };
31 | case FAILURE(ACTION_TYPES.GET_SESSION):
32 | return {
33 | ...state,
34 | loading: false,
35 | isAuthenticated: false,
36 | errorMessage: action.payload
37 | };
38 | case ACTION_TYPES.LOGOUT:
39 | return {
40 | ...initialState
41 | };
42 | case SUCCESS(ACTION_TYPES.GET_SESSION): {
43 | const isAuthenticated = action.payload && action.payload.data && action.payload.data.activated;
44 | return {
45 | ...state,
46 | isAuthenticated,
47 | loading: false,
48 | account: action.payload.data
49 | };
50 | }
51 | case ACTION_TYPES.ERROR_MESSAGE:
52 | return {
53 | ...initialState,
54 | redirectMessage: action.message
55 | };
56 | case ACTION_TYPES.CLEAR_AUTH:
57 | return {
58 | ...state,
59 | loading: false,
60 | isAuthenticated: false
61 | };
62 | default:
63 | return state;
64 | }
65 | };
66 |
67 | export const displayAuthError = message => ({ type: ACTION_TYPES.ERROR_MESSAGE, message });
68 |
69 | export const getSession = () => dispatch =>
70 | dispatch({
71 | type: ACTION_TYPES.GET_SESSION,
72 | payload: axios.get('/api/account')
73 | });
74 |
75 | export const logout = () => async dispatch => {
76 | await dispatch({
77 | type: ACTION_TYPES.LOGOUT,
78 | payload: axios.post('/api/logout', {})
79 | });
80 | dispatch(getSession());
81 | };
82 |
83 | export const clearAuthentication = messageKey => (dispatch, getState) => {
84 | dispatch(displayAuthError(messageKey));
85 | dispatch({
86 | type: ACTION_TYPES.CLEAR_AUTH
87 | });
88 | };
89 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/reducers/index.ts:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import { loadingBarReducer as loadingBar } from 'react-redux-loading-bar';
3 |
4 | import locale, { LocaleState } from './locale';
5 | import authentication, { AuthenticationState } from './authentication';
6 | import applicationProfile, { ApplicationProfileState } from './application-profile';
7 |
8 | import administration, { AdministrationState } from 'app/modules/administration/administration.reducer';
9 | import userManagement, { UserManagementState } from './user-management';
10 | // prettier-ignore
11 | import album, {
12 | AlbumState
13 | } from 'app/entities/album/album.reducer';
14 | // prettier-ignore
15 | import photo, {
16 | PhotoState
17 | } from 'app/entities/photo/photo.reducer';
18 | // prettier-ignore
19 | import tag, {
20 | TagState
21 | } from 'app/entities/tag/tag.reducer';
22 | /* jhipster-needle-add-reducer-import - JHipster will add reducer here */
23 |
24 | export interface IRootState {
25 | readonly authentication: AuthenticationState;
26 | readonly locale: LocaleState;
27 | readonly applicationProfile: ApplicationProfileState;
28 | readonly administration: AdministrationState;
29 | readonly userManagement: UserManagementState;
30 | readonly album: AlbumState;
31 | readonly photo: PhotoState;
32 | readonly tag: TagState;
33 | /* jhipster-needle-add-reducer-type - JHipster will add reducer type here */
34 | readonly loadingBar: any;
35 | }
36 |
37 | const rootReducer = combineReducers({
38 | authentication,
39 | locale,
40 | applicationProfile,
41 | administration,
42 | userManagement,
43 | album,
44 | photo,
45 | tag,
46 | /* jhipster-needle-add-reducer-combine - JHipster will add reducer here */
47 | loadingBar
48 | });
49 |
50 | export default rootReducer;
51 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/reducers/locale.ts:
--------------------------------------------------------------------------------
1 | export const ACTION_TYPES = {
2 | SET_LOCALE: 'locale/SET_LOCALE'
3 | };
4 |
5 | const initialState = {
6 | currentLocale: 'en'
7 | };
8 |
9 | export type LocaleState = Readonly;
10 |
11 | export default (state: LocaleState = initialState, action): LocaleState => {
12 | switch (action.type) {
13 | case ACTION_TYPES.SET_LOCALE:
14 | return {
15 | currentLocale: action.locale || initialState.currentLocale
16 | };
17 | default:
18 | return state;
19 | }
20 | };
21 |
22 | export const setLocale = locale => ({
23 | type: ACTION_TYPES.SET_LOCALE,
24 | locale
25 | });
26 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/reducers/user-management.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { ICrudGetAllAction } from 'react-jhipster';
3 |
4 | import { REQUEST, SUCCESS, FAILURE } from 'app/shared/reducers/action-type.util';
5 | import { IUser } from 'app/shared/model/user.model';
6 |
7 | export const ACTION_TYPES = {
8 | FETCH_USERS: 'userManagement/FETCH_USERS',
9 | RESET: 'userManagement/RESET'
10 | };
11 |
12 | const initialState = {
13 | errorMessage: null,
14 | users: [] as ReadonlyArray
15 | };
16 |
17 | export type UserManagementState = Readonly;
18 |
19 | // Reducer
20 | export default (state: UserManagementState = initialState, action): UserManagementState => {
21 | switch (action.type) {
22 | case REQUEST(ACTION_TYPES.FETCH_USERS):
23 | return {
24 | ...state
25 | };
26 | case FAILURE(ACTION_TYPES.FETCH_USERS):
27 | return {
28 | ...state,
29 | errorMessage: action.payload
30 | };
31 | case SUCCESS(ACTION_TYPES.FETCH_USERS):
32 | return {
33 | ...state,
34 | users: action.payload.data
35 | };
36 | case ACTION_TYPES.RESET:
37 | return {
38 | ...state,
39 | users: []
40 | };
41 | default:
42 | return state;
43 | }
44 | };
45 |
46 | const apiUrl = '/api/users';
47 | // Actions
48 | export const getUsers: ICrudGetAllAction = (page, size, sort) => {
49 | const requestUrl = `${apiUrl}${sort ? `?page=${page}&size=${size}&sort=${sort}` : ''}`;
50 | return {
51 | type: ACTION_TYPES.FETCH_USERS,
52 | payload: axios.get(requestUrl)
53 | };
54 | };
55 |
56 | export const reset = () => ({
57 | type: ACTION_TYPES.RESET
58 | });
59 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/util/date-utils.ts:
--------------------------------------------------------------------------------
1 | import * as moment from 'moment';
2 |
3 | import { APP_LOCAL_DATETIME_FORMAT } from 'app/config/constants';
4 |
5 | export const convertDateTimeFromServer = date => (date ? moment(date).format(APP_LOCAL_DATETIME_FORMAT) : null);
6 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/util/entity-utils.ts:
--------------------------------------------------------------------------------
1 | import { pick } from 'lodash';
2 |
3 | /**
4 | * Removes fields with an 'id' field that equals ''.
5 | * This function was created to prevent entities to be sent to
6 | * the server with relationship fields with empty an empty id and thus
7 | * resulting in a 500.
8 | *
9 | * @param entity Object to clean.
10 | */
11 | export const cleanEntity = entity => {
12 | const keysToKeep = Object.keys(entity).filter(k => !(entity[k] instanceof Object) || (entity[k]['id'] !== '' && entity[k]['id'] !== -1));
13 |
14 | return pick(entity, keysToKeep);
15 | };
16 |
17 | /**
18 | * Will return a list of values according to the given keys.
19 | * This function is used to get a values in Many-to-many relations.
20 | *
21 | * @param keyList Keys.
22 | * @param data Array that contains the values.
23 | * @param fieldName Name of the field that contains the key in the value.
24 | */
25 | export const keysToValues = (keyList: ReadonlyArray, data: ReadonlyArray, fieldName: string) =>
26 | keyList.map((k: any) => data.find((e: any) => e[fieldName] === k));
27 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/util/pagination.constants.ts:
--------------------------------------------------------------------------------
1 | export const ITEMS_PER_PAGE = 20;
2 |
--------------------------------------------------------------------------------
/src/main/webapp/app/shared/util/url-utils.ts:
--------------------------------------------------------------------------------
1 | export const getLoginUrl = () => {
2 | let port = location.port ? `:${location.port}` : '';
3 | if (port === ':9000') {
4 | port = ':8080';
5 | }
6 | return `//${location.hostname}${port}/login`;
7 | };
8 |
--------------------------------------------------------------------------------
/src/main/webapp/app/typings.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.json' {
2 | const value: any;
3 | export default value;
4 | }
5 |
--------------------------------------------------------------------------------
/src/main/webapp/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oktadev/okta-react-photo-gallery-example/c0ba0bbfbcd66ca20c7a2637e8fbf6a18892a0f3/src/main/webapp/favicon.ico
--------------------------------------------------------------------------------
/src/main/webapp/i18n/en/activate.json:
--------------------------------------------------------------------------------
1 | {
2 | "activate": {
3 | "title": "Activation",
4 | "messages": {
5 | "success": "Your user account has been activated. Please ",
6 | "error": "Your user could not be activated. Please use the registration form to sign up."
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/en/album.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "galleryApp": {
4 | "album" : {
5 | "home": {
6 | "title": "Albums",
7 | "createLabel": "Create a new Album",
8 | "createOrEditLabel": "Create or edit a Album"
9 | },
10 | "created": "A new Album is created with identifier {{ param }}",
11 | "updated": "A Album is updated with identifier {{ param }}",
12 | "deleted": "A Album is deleted with identifier {{ param }}",
13 | "delete": {
14 | "question": "Are you sure you want to delete Album {{ id }}?"
15 | },
16 | "detail": {
17 | "title": "Album"
18 | },
19 | "title": "Title",
20 | "description": "Description",
21 | "created": "Created",
22 | "user": "User"
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/en/audits.json:
--------------------------------------------------------------------------------
1 | {
2 | "audits": {
3 | "title": "Audits",
4 | "filter": {
5 | "title": "Filter per date",
6 | "from": "from",
7 | "to": "to",
8 | "button": {
9 | "weeks": "Weeks",
10 | "today": "today",
11 | "clear": "clear",
12 | "close": "close"
13 | }
14 | },
15 | "table": {
16 | "header": {
17 | "principal": "User",
18 | "date": "Date",
19 | "status": "State",
20 | "data": "Extra data"
21 | },
22 | "data": {
23 | "remoteAddress": "Remote Address:"
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/en/configuration.json:
--------------------------------------------------------------------------------
1 | {
2 | "configuration": {
3 | "title": "Configuration",
4 | "filter": "Filter (by prefix)",
5 | "table": {
6 | "prefix": "Prefix",
7 | "properties": "Properties"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/en/error.json:
--------------------------------------------------------------------------------
1 | {
2 | "error": {
3 | "title": "Error page!",
4 | "http": {
5 | "400": "Bad request.",
6 | "403": "You are not authorized to access this page.",
7 | "405": "The HTTP verb you used is not supported for this URL.",
8 | "500": "Internal server error."
9 | },
10 | "concurrencyFailure": "Another user modified this data at the same time as you. Your changes were rejected.",
11 | "validation": "Validation error on the server."
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/en/gateway.json:
--------------------------------------------------------------------------------
1 | {
2 | "gateway": {
3 | "title": "Gateway",
4 | "routes": {
5 | "title": "Current routes",
6 | "url": "URL",
7 | "service": "service",
8 | "servers": "Available servers",
9 | "error": "Warning: no server available!"
10 | },
11 | "refresh": {
12 | "button": "Refresh"
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/en/health.json:
--------------------------------------------------------------------------------
1 | {
2 | "health": {
3 | "title": "Health Checks",
4 | "refresh.button": "Refresh",
5 | "stacktrace": "Stacktrace",
6 | "details": {
7 | "details": "Details",
8 | "properties": "Properties",
9 | "name": "Name",
10 | "value": "Value",
11 | "error": "Error"
12 | },
13 | "indicator": {
14 | "diskSpace": "Disk space",
15 | "mail": "Email",
16 | "db": "Database"
17 | },
18 | "table": {
19 | "service": "Service name",
20 | "status": "Status"
21 | },
22 | "status": {
23 | "UP": "UP",
24 | "DOWN": "DOWN"
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/en/home.json:
--------------------------------------------------------------------------------
1 | {
2 | "home": {
3 | "title": "Welcome, Java Hipster!",
4 | "subtitle": "This is your homepage",
5 | "logged": {
6 | "message": "You are logged in as user \"{{username}}\"."
7 | },
8 | "question": "If you have any question on JHipster:",
9 | "link": {
10 | "homepage": "JHipster homepage",
11 | "stackoverflow": "JHipster on Stack Overflow",
12 | "bugtracker": "JHipster bug tracker",
13 | "chat": "JHipster public chat room",
14 | "follow": "follow @java_hipster on Twitter"
15 | },
16 | "like": "If you like JHipster, don't forget to give us a star on",
17 | "github": "GitHub"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/en/login.json:
--------------------------------------------------------------------------------
1 | {
2 | "login": {
3 | "title": "Sign in",
4 | "form": {
5 | "password": "Password",
6 | "password.placeholder": "Your password",
7 | "rememberme": "Remember me",
8 | "button": "Sign in"
9 | },
10 | "messages": {
11 | "error": {
12 | "authentication": "Failed to sign in! Please check your credentials and try again."
13 | }
14 | },
15 | "password" : {
16 | "forgot": "Did you forget your password?"
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/en/logs.json:
--------------------------------------------------------------------------------
1 | {
2 | "logs": {
3 | "title": "Logs",
4 | "nbloggers": "There are {{ total }} loggers.",
5 | "filter": "Filter",
6 | "table": {
7 | "name": "Name",
8 | "level": "Level"
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/en/password.json:
--------------------------------------------------------------------------------
1 | {
2 | "password": {
3 | "title": "Password for [{{username}}]",
4 | "form": {
5 | "button": "Save"
6 | },
7 | "messages": {
8 | "error": "An error has occurred! The password could not be changed.",
9 | "success": "Password changed!"
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/en/photo.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "galleryApp": {
4 | "photo" : {
5 | "home": {
6 | "title": "Photos",
7 | "createLabel": "Create a new Photo",
8 | "createOrEditLabel": "Create or edit a Photo"
9 | },
10 | "created": "A new Photo is created with identifier {{ param }}",
11 | "updated": "A Photo is updated with identifier {{ param }}",
12 | "deleted": "A Photo is deleted with identifier {{ param }}",
13 | "delete": {
14 | "question": "Are you sure you want to delete Photo {{ id }}?"
15 | },
16 | "detail": {
17 | "title": "Photo"
18 | },
19 | "title": "Title",
20 | "description": "Description",
21 | "image": "Image",
22 | "height": "Height",
23 | "width": "Width",
24 | "taken": "Taken",
25 | "uploaded": "Uploaded",
26 | "album": "Album",
27 | "tag": "Tag"
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/en/register.json:
--------------------------------------------------------------------------------
1 | {
2 | "register": {
3 | "title": "Registration",
4 | "form": {
5 | "button": "Register"
6 | },
7 | "messages": {
8 | "validate": {
9 | "login": {
10 | "required": "Your username is required.",
11 | "minlength": "Your username is required to be at least 1 character.",
12 | "maxlength": "Your username cannot be longer than 50 characters.",
13 | "pattern": "Your username can only contain letters and digits."
14 | }
15 | },
16 | "success": "Registration saved! Please check your email for confirmation.",
17 | "error": {
18 | "fail": "Registration failed! Please try again later.",
19 | "userexists": "Login name already registered! Please choose another one.",
20 | "emailexists": "Email is already in use! Please choose another one."
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/en/reset.json:
--------------------------------------------------------------------------------
1 | {
2 | "reset": {
3 | "request": {
4 | "title": "Reset your password",
5 | "form": {
6 | "button": "Reset password"
7 | },
8 | "messages": {
9 | "info": "Enter the email address you used to register",
10 | "success": "Check your emails for details on how to reset your password.",
11 | "notfound": "Email address isn't registered! Please check and try again"
12 | }
13 | },
14 | "finish" : {
15 | "title": "Reset password",
16 | "form": {
17 | "button": "Validate new password"
18 | },
19 | "messages": {
20 | "info": "Choose a new password",
21 | "success": "Your password has been reset. Please ",
22 | "keymissing": "The reset key is missing.",
23 | "error": "Your password couldn't be reset. Remember a password request is only valid for 24 hours."
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/en/sessions.json:
--------------------------------------------------------------------------------
1 | {
2 | "sessions": {
3 | "title": "Active sessions for [{{username}}]",
4 | "table": {
5 | "ipaddress": "IP address",
6 | "useragent": "User Agent",
7 | "date": "Date",
8 | "button": "Invalidate"
9 | },
10 | "messages": {
11 | "success": "Session invalidated!",
12 | "error": "An error has occurred! The session could not be invalidated."
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/en/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "settings": {
3 | "title": "User settings for [{{username}}]",
4 | "form": {
5 | "firstname": "First Name",
6 | "firstname.placeholder": "Your first name",
7 | "lastname": "Last Name",
8 | "lastname.placeholder": "Your last name",
9 | "language": "Language",
10 | "button": "Save"
11 | },
12 | "messages": {
13 | "error": {
14 | "fail": "An error has occurred! Settings could not be saved.",
15 | "emailexists": "Email is already in use! Please choose another one."
16 | },
17 | "success": "Settings saved!",
18 | "validate": {
19 | "firstname": {
20 | "required": "Your first name is required.",
21 | "minlength": "Your first name is required to be at least 1 character",
22 | "maxlength": "Your first name cannot be longer than 50 characters"
23 | },
24 | "lastname": {
25 | "required": "Your last name is required.",
26 | "minlength": "Your last name is required to be at least 1 character",
27 | "maxlength": "Your last name cannot be longer than 50 characters"
28 | }
29 | }
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/en/tag.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "galleryApp": {
4 | "tag" : {
5 | "home": {
6 | "title": "Tags",
7 | "createLabel": "Create a new Tag",
8 | "createOrEditLabel": "Create or edit a Tag"
9 | },
10 | "created": "A new Tag is created with identifier {{ param }}",
11 | "updated": "A Tag is updated with identifier {{ param }}",
12 | "deleted": "A Tag is deleted with identifier {{ param }}",
13 | "delete": {
14 | "question": "Are you sure you want to delete Tag {{ id }}?"
15 | },
16 | "detail": {
17 | "title": "Tag"
18 | },
19 | "name": "Name",
20 | "photo": "Photo"
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/en/user-management.json:
--------------------------------------------------------------------------------
1 | {
2 | "userManagement": {
3 | "home": {
4 | "title": "Users",
5 | "createLabel": "Create a new user",
6 | "createOrEditLabel": "Create or edit a user"
7 | },
8 | "created": "A new user is created with identifier {{ param }}",
9 | "updated": "An user is updated with identifier {{ param }}",
10 | "deleted": "An user is deleted with identifier {{ param }}",
11 | "delete": {
12 | "question": "Are you sure you want to delete user {{ login }}?"
13 | },
14 | "detail": {
15 | "title": "User"
16 | },
17 | "login": "Login",
18 | "firstName": "First name",
19 | "lastName": "Last name",
20 | "email": "Email",
21 | "activated": "Activated",
22 | "deactivated": "Deactivated",
23 | "profiles": "Profiles",
24 | "langKey": "Language",
25 | "createdBy": "Created by",
26 | "createdDate": "Created date",
27 | "lastModifiedBy": "Modified by",
28 | "lastModifiedDate": "Modified date"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/fr/activate.json:
--------------------------------------------------------------------------------
1 | {
2 | "activate": {
3 | "title": "Activation",
4 | "messages": {
5 | "success": "Votre compte utilisateur a été activé. Merci de vous ",
6 | "error": "Votre compte utilisateur n'a pas pu être activé. Utilisez le formulaire d'enregistrement pour en créer un nouveau."
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/fr/album.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "galleryApp": {
4 | "album" : {
5 | "home": {
6 | "title": "Albums",
7 | "createLabel": "Créer un nouveau Album",
8 | "createOrEditLabel": "Créer ou éditer un Album"
9 | },
10 | "created": "Un nouveau Album a été créé avec l'identifiant {{ param }}",
11 | "updated": "Le Album avec l'identifiant {{ param }} a été mis à jour",
12 | "deleted": "Le Album avec l'identifiant {{ param }} a été supprimé",
13 | "delete": {
14 | "question": "Etes-vous certain de vouloir supprimer le Album {{ id }} ?"
15 | },
16 | "detail": {
17 | "title": "Album"
18 | },
19 | "title": "Title",
20 | "description": "Description",
21 | "created": "Created",
22 | "user": "User"
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/fr/audits.json:
--------------------------------------------------------------------------------
1 | {
2 | "audits": {
3 | "title": "Audits",
4 | "filter": {
5 | "title": "Filtrer par date",
6 | "from": "De",
7 | "to": "à",
8 | "button": {
9 | "weeks": "Semaines",
10 | "today": "Aujourd'hui",
11 | "clear": "Effacer",
12 | "close": "Fermer"
13 | }
14 | },
15 | "table": {
16 | "header": {
17 | "principal": "Utilisateur",
18 | "date": "Date",
19 | "status": "Status",
20 | "data": "Autres données"
21 | },
22 | "data": {
23 | "remoteAddress": "Adresse Distante :"
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/fr/configuration.json:
--------------------------------------------------------------------------------
1 | {
2 | "configuration": {
3 | "title": "Configuration",
4 | "filter": "Filtrer (par préfixe)",
5 | "table": {
6 | "prefix": "Préfixe",
7 | "properties": "Propriétés"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/fr/error.json:
--------------------------------------------------------------------------------
1 | {
2 | "error": {
3 | "title": "Page d'erreur !",
4 | "http": {
5 | "400": "Mauvaise requête.",
6 | "403": "Vous n'avez pas les droits pour accéder à cette page.",
7 | "405": "Le verbe HTTP que vous avez utilisé n'est pas reconnu par cet URL.",
8 | "500": "Erreur interne du serveur."
9 | },
10 | "concurrencyFailure": "Un autre utilisateur a modifié ces données en même temps que vous. Vos changements n'ont pas été sauvegardés.",
11 | "validation": "Erreur de validation côté serveur."
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/fr/gateway.json:
--------------------------------------------------------------------------------
1 | {
2 | "gateway": {
3 | "title": "Gateway",
4 | "routes": {
5 | "title": "Routes actuelles",
6 | "url": "URL",
7 | "service": "Service",
8 | "servers": "Serveurs disponibles",
9 | "error": "Attention : aucun serveur disponible !"
10 | },
11 | "refresh": {
12 | "button": "Rafraîchir"
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/fr/health.json:
--------------------------------------------------------------------------------
1 | {
2 | "health": {
3 | "title": "Diagnostics",
4 | "refresh.button": "Rafraichir",
5 | "stacktrace": "Stacktrace",
6 | "details": {
7 | "details": "Détails",
8 | "properties": "Propriétés",
9 | "name": "Nom",
10 | "value": "Valeur",
11 | "error": "Erreur"
12 | },
13 | "indicator": {
14 | "diskSpace": "Espace disque",
15 | "mail": "Email",
16 | "db": "Base de données"
17 | },
18 | "table": {
19 | "service": "Nom du service",
20 | "status": "Etat"
21 | },
22 | "status": {
23 | "UP": "DISPONIBLE",
24 | "DOWN": "HORS SERVICE"
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/fr/home.json:
--------------------------------------------------------------------------------
1 | {
2 | "home": {
3 | "title": "Bienvenue, Java Hipster !",
4 | "subtitle": "Ceci est votre page d'accueil",
5 | "logged": {
6 | "message": "Vous êtes connecté en tant que \"{{username}}\"."
7 | },
8 | "question": "Si vous avez des questions à propos de JHipster :",
9 | "link": {
10 | "homepage": "Page d'accueil de JHipster",
11 | "stackoverflow": "JHipster sur Stack Overflow",
12 | "bugtracker": "JHipster bug tracker",
13 | "chat": "JHipster public chat room",
14 | "follow": "Suivez @java_hipster sur Twitter"
15 | },
16 | "like": "Si vous aimez JHipster, donnez nous une étoile sur",
17 | "github": "GitHub "
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/fr/login.json:
--------------------------------------------------------------------------------
1 | {
2 | "login": {
3 | "title": "Authentification",
4 | "form": {
5 | "password": "Mot de passe",
6 | "password.placeholder": "Votre mot de passe",
7 | "rememberme": "Garder la session ouverte",
8 | "button": "Connexion"
9 | },
10 | "messages": {
11 | "error": {
12 | "authentication": "Erreur d'authentification ! Veuillez vérifier vos identifiants de connexion."
13 | }
14 | },
15 | "password" : {
16 | "forgot": "Avez-vous oublié votre mot de passe ?"
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/fr/logs.json:
--------------------------------------------------------------------------------
1 | {
2 | "logs": {
3 | "title": "Logs",
4 | "nbloggers": "Total de {{ total }} \"loggers\".",
5 | "filter": "Filtrer",
6 | "table": {
7 | "name": "Nom",
8 | "level": "Niveau"
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/fr/password.json:
--------------------------------------------------------------------------------
1 | {
2 | "password": {
3 | "title": "Changer le mot de passe pour [{{username}}]",
4 | "form": {
5 | "button": "Sauvegarder"
6 | },
7 | "messages": {
8 | "error": "Une erreur est survenue ! Le mot de passe n'a pas pu être modifié.",
9 | "success": "Le mot de passe a été modifié !"
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/fr/photo.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "galleryApp": {
4 | "photo" : {
5 | "home": {
6 | "title": "Photos",
7 | "createLabel": "Créer un nouveau Photo",
8 | "createOrEditLabel": "Créer ou éditer un Photo"
9 | },
10 | "created": "Un nouveau Photo a été créé avec l'identifiant {{ param }}",
11 | "updated": "Le Photo avec l'identifiant {{ param }} a été mis à jour",
12 | "deleted": "Le Photo avec l'identifiant {{ param }} a été supprimé",
13 | "delete": {
14 | "question": "Etes-vous certain de vouloir supprimer le Photo {{ id }} ?"
15 | },
16 | "detail": {
17 | "title": "Photo"
18 | },
19 | "title": "Title",
20 | "description": "Description",
21 | "image": "Image",
22 | "height": "Height",
23 | "width": "Width",
24 | "taken": "Taken",
25 | "uploaded": "Uploaded",
26 | "album": "Album",
27 | "tag": "Tag"
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/fr/register.json:
--------------------------------------------------------------------------------
1 | {
2 | "register": {
3 | "title": "Création de compte utilisateur",
4 | "form": {
5 | "button": "Enregistrement"
6 | },
7 | "messages": {
8 | "validate": {
9 | "login": {
10 | "required": "Votre nom d'utilisateur est obligatoire.",
11 | "minlength": "Votre nom d'utilisateur doit contenir plus d'un caractère.",
12 | "maxlength": "Votre nom d'utilisateur ne peut pas contenir plus de 50 caractères.",
13 | "pattern": "Votre nom d'utilisateur ne peut contenir que des lettres minuscules ou des nombres."
14 | }
15 | },
16 | "success": "Compte enregistré ! Merci de vérifier votre email de confirmation.",
17 | "error": {
18 | "fail": "Compte non créé ! Merci d'essayer à nouveau plus tard.",
19 | "userexists": "Ce compte utilisateur existe déjà ! Veuillez en choisir un autre.",
20 | "emailexists": "Cet email est déjà utilisé ! Veuillez en choisir un autre."
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/fr/reset.json:
--------------------------------------------------------------------------------
1 | {
2 | "reset": {
3 | "request": {
4 | "title": "Réinitialiser son mot de passe",
5 | "form": {
6 | "button": "Réinitialiser le mot de passe"
7 | },
8 | "messages": {
9 | "info": "Veuillez renseigner l'adresse email utilisée pour vous enregistrer",
10 | "success": "Veuillez vérifier vos nouveaux emails et suivre les instructions pour réinitialiser votre mot de passe.",
11 | "notfound": "L'adresse email n'existe pas ! Merci de la vérifier et de réessayer."
12 | }
13 | },
14 | "finish" : {
15 | "title": "Réinitialisation du mot de passe",
16 | "form": {
17 | "button": "Réinitialiser le mot de passe"
18 | },
19 | "messages": {
20 | "info": "Choisir un nouveau mot de passe",
21 | "success": "Votre mot de passe a été réinitialisé. Merci de ",
22 | "keymissing": "La clef de réinitilisation est manquante",
23 | "error": "Votre mot de passe n'a pas pu être réinitialisé. La demande de réinitialisation n'est valable que 24 heures."
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/fr/sessions.json:
--------------------------------------------------------------------------------
1 | {
2 | "sessions": {
3 | "title": "Sessions actives de [{{username}}]",
4 | "table": {
5 | "ipaddress": "Adresse IP",
6 | "useragent": "User Agent",
7 | "date": "Date",
8 | "button": "Invalider"
9 | },
10 | "messages": {
11 | "success": "La session a été invalidée !",
12 | "error": "Une erreur est survenue ! La session ne peut pas être invalidée."
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/fr/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "settings": {
3 | "title": "Profil de l'utilisateur [{{username}}]",
4 | "form": {
5 | "firstname": "Prénom",
6 | "firstname.placeholder": "Votre prénom",
7 | "lastname": "Nom",
8 | "lastname.placeholder": "Votre nom",
9 | "language": "Langue",
10 | "button": "Sauvegarder"
11 | },
12 | "messages": {
13 | "error": {
14 | "fail": "Une erreur est survenue ! Votre profil n'a pas été sauvegardé.",
15 | "emailexists": "Cet email est déjà utilisé ! Veuillez en choisir un autre."
16 | },
17 | "success": "Votre profil a été sauvegardé !",
18 | "validate": {
19 | "firstname": {
20 | "required": "Votre prénom est requis.",
21 | "minlength": "Votre prénom doit comporter au moins un caractère.",
22 | "maxlength": "Votre prénom ne doit pas comporter plus de 50 caractères."
23 | },
24 | "lastname": {
25 | "required": "Votre nom est requis.",
26 | "minlength": "Votre nom doit comporter au moins un caractère.",
27 | "maxlength": "Votre nom ne doit pas comporter plus de 50 caractères."
28 | }
29 | }
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/fr/tag.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "galleryApp": {
4 | "tag" : {
5 | "home": {
6 | "title": "Tags",
7 | "createLabel": "Créer un nouveau Tag",
8 | "createOrEditLabel": "Créer ou éditer un Tag"
9 | },
10 | "created": "Un nouveau Tag a été créé avec l'identifiant {{ param }}",
11 | "updated": "Le Tag avec l'identifiant {{ param }} a été mis à jour",
12 | "deleted": "Le Tag avec l'identifiant {{ param }} a été supprimé",
13 | "delete": {
14 | "question": "Etes-vous certain de vouloir supprimer le Tag {{ id }} ?"
15 | },
16 | "detail": {
17 | "title": "Tag"
18 | },
19 | "name": "Name",
20 | "photo": "Photo"
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/webapp/i18n/fr/user-management.json:
--------------------------------------------------------------------------------
1 | {
2 | "userManagement": {
3 | "home": {
4 | "title": "Utilisateurs",
5 | "createLabel": "Créer un nouvel utilisateur",
6 | "createOrEditLabel": "Créer ou éditer un utilisateur"
7 | },
8 | "created": "L'utilisateur {{ param }} a été créé.",
9 | "updated": "L'utilisateur {{ param }} a été mis à jour.",
10 | "deleted": "L'utilisateur {{ param }} a été supprimé.",
11 | "delete": {
12 | "question": "Etes-vous certain de vouloir supprimer l'utilisateur {{ login }} ?"
13 | },
14 | "detail": {
15 | "title": "Utilisateur"
16 | },
17 | "login": "Login",
18 | "firstName": "Prénom",
19 | "lastName": "Nom",
20 | "email": "Email",
21 | "activated": "Activé",
22 | "deactivated": "Désactivé",
23 | "profiles": "Droits",
24 | "langKey": "Langue",
25 | "createdBy": "Créé par",
26 | "createdDate": "Créé le",
27 | "lastModifiedBy": "Modifié par",
28 | "lastModifiedDate": "Modifié le"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/webapp/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | gallery
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
20 |
21 |
24 |
31 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/main/webapp/manifest.webapp:
--------------------------------------------------------------------------------
1 | {
2 | "name": "React Photo Gallery",
3 | "short_name": "Gallery",
4 | "icons": [
5 | {
6 | "src": "./static/images/hipster192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "./static/images/hipster256.png",
12 | "sizes": "256x256",
13 | "type": "image/png"
14 | },
15 | {
16 | "src": "./static/images/hipster384.png",
17 | "sizes": "384x384",
18 | "type": "image/png"
19 | },
20 | {
21 | "src": "./static/images/hipster512.png",
22 | "sizes": "512x512",
23 | "type": "image/png"
24 | }
25 | ],
26 | "theme_color": "#000000",
27 | "background_color": "#e0e0e0",
28 | "start_url": "/index.html",
29 | "display": "standalone",
30 | "orientation": "portrait"
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/webapp/robots.txt:
--------------------------------------------------------------------------------
1 | # robotstxt.org/
2 |
3 | User-agent: *
4 | Disallow: /api/account
5 | Disallow: /api/audits/
6 | Disallow: /api/logs/
7 | Disallow: /api/users/
8 | Disallow: /management/
9 | Disallow: /v2/api-docs/
10 |
--------------------------------------------------------------------------------
/src/main/webapp/static/images/hipster.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oktadev/okta-react-photo-gallery-example/c0ba0bbfbcd66ca20c7a2637e8fbf6a18892a0f3/src/main/webapp/static/images/hipster.png
--------------------------------------------------------------------------------
/src/main/webapp/static/images/hipster192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oktadev/okta-react-photo-gallery-example/c0ba0bbfbcd66ca20c7a2637e8fbf6a18892a0f3/src/main/webapp/static/images/hipster192.png
--------------------------------------------------------------------------------
/src/main/webapp/static/images/hipster256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oktadev/okta-react-photo-gallery-example/c0ba0bbfbcd66ca20c7a2637e8fbf6a18892a0f3/src/main/webapp/static/images/hipster256.png
--------------------------------------------------------------------------------
/src/main/webapp/static/images/hipster2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oktadev/okta-react-photo-gallery-example/c0ba0bbfbcd66ca20c7a2637e8fbf6a18892a0f3/src/main/webapp/static/images/hipster2x.png
--------------------------------------------------------------------------------
/src/main/webapp/static/images/hipster384.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oktadev/okta-react-photo-gallery-example/c0ba0bbfbcd66ca20c7a2637e8fbf6a18892a0f3/src/main/webapp/static/images/hipster384.png
--------------------------------------------------------------------------------
/src/main/webapp/static/images/hipster512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oktadev/okta-react-photo-gallery-example/c0ba0bbfbcd66ca20c7a2637e8fbf6a18892a0f3/src/main/webapp/static/images/hipster512.png
--------------------------------------------------------------------------------
/src/main/webapp/static/images/logo-jhipster.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oktadev/okta-react-photo-gallery-example/c0ba0bbfbcd66ca20c7a2637e8fbf6a18892a0f3/src/main/webapp/static/images/logo-jhipster.png
--------------------------------------------------------------------------------
/src/main/webapp/swagger-ui/dist/images/throbber.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oktadev/okta-react-photo-gallery-example/c0ba0bbfbcd66ca20c7a2637e8fbf6a18892a0f3/src/main/webapp/swagger-ui/dist/images/throbber.gif
--------------------------------------------------------------------------------
/src/test/java/com/okta/developer/config/WebConfigurerTestController.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.config;
2 |
3 | import org.springframework.web.bind.annotation.GetMapping;
4 | import org.springframework.web.bind.annotation.RestController;
5 |
6 | @RestController
7 | public class WebConfigurerTestController {
8 |
9 | @GetMapping("/api/test-cors")
10 | public void testCorsOnApiPath() {
11 | }
12 |
13 | @GetMapping("/test/test-cors")
14 | public void testCorsOnOtherPath() {
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/test/java/com/okta/developer/web/rest/util/PaginationUtilUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.okta.developer.web.rest.util;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import static org.junit.Assert.assertNotNull;
5 | import static org.junit.Assert.assertTrue;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | import org.junit.Test;
11 | import org.springframework.data.domain.Page;
12 | import org.springframework.data.domain.PageImpl;
13 | import org.springframework.data.domain.PageRequest;
14 | import org.springframework.http.HttpHeaders;
15 |
16 | /**
17 | * Tests based on parsing algorithm in app/components/util/pagination-util.service.js
18 | *
19 | * @see PaginationUtil
20 | */
21 | public class PaginationUtilUnitTest {
22 |
23 | @Test
24 | public void generatePaginationHttpHeadersTest() {
25 | String baseUrl = "/api/_search/example";
26 | List content = new ArrayList<>();
27 | Page page = new PageImpl<>(content, PageRequest.of(6, 50), 400L);
28 | HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, baseUrl);
29 | List strHeaders = headers.get(HttpHeaders.LINK);
30 | assertNotNull(strHeaders);
31 | assertTrue(strHeaders.size() == 1);
32 | String headerData = strHeaders.get(0);
33 | assertTrue(headerData.split(",").length == 4);
34 | String expectedData = "; rel=\"next\","
35 | + "; rel=\"prev\","
36 | + "; rel=\"last\","
37 | + "; rel=\"first\"";
38 | assertEquals(expectedData, headerData);
39 | List xTotalCountHeaders = headers.get("X-Total-Count");
40 | assertTrue(xTotalCountHeaders.size() == 1);
41 | assertTrue(Long.valueOf(xTotalCountHeaders.get(0)).equals(400L));
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/javascript/e2e/entities/album/album-update.page-object.ts:
--------------------------------------------------------------------------------
1 | import { element, by, ElementFinder } from 'protractor';
2 |
3 | export default class AlbumUpdatePage {
4 | pageTitle: ElementFinder = element(by.id('galleryApp.album.home.createOrEditLabel'));
5 | saveButton: ElementFinder = element(by.id('save-entity'));
6 | cancelButton: ElementFinder = element(by.id('cancel-save'));
7 | titleInput: ElementFinder = element(by.css('input#album-title'));
8 | descriptionInput: ElementFinder = element(by.css('input#album-description'));
9 | createdInput: ElementFinder = element(by.css('input#album-created'));
10 | userSelect: ElementFinder = element(by.css('select#album-user'));
11 |
12 | getPageTitle() {
13 | return this.pageTitle;
14 | }
15 |
16 | setTitleInput(title) {
17 | this.titleInput.sendKeys(title);
18 | }
19 |
20 | getTitleInput() {
21 | return this.titleInput.getAttribute('value');
22 | }
23 |
24 | setDescriptionInput(description) {
25 | this.descriptionInput.sendKeys(description);
26 | }
27 |
28 | getDescriptionInput() {
29 | return this.descriptionInput.getAttribute('value');
30 | }
31 |
32 | setCreatedInput(created) {
33 | this.createdInput.sendKeys(created);
34 | }
35 |
36 | getCreatedInput() {
37 | return this.createdInput.getAttribute('value');
38 | }
39 |
40 | userSelectLastOption() {
41 | this.userSelect
42 | .all(by.tagName('option'))
43 | .last()
44 | .click();
45 | }
46 |
47 | userSelectOption(option) {
48 | this.userSelect.sendKeys(option);
49 | }
50 |
51 | getUserSelect() {
52 | return this.userSelect;
53 | }
54 |
55 | getUserSelectedOption() {
56 | return this.userSelect.element(by.css('option:checked')).getText();
57 | }
58 |
59 | save() {
60 | return this.saveButton.click();
61 | }
62 |
63 | cancel() {
64 | this.cancelButton.click();
65 | }
66 |
67 | getSaveButton() {
68 | return this.saveButton;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/test/javascript/e2e/entities/album/album.page-object.ts:
--------------------------------------------------------------------------------
1 | import { element, by, ElementFinder } from 'protractor';
2 |
3 | export default class AlbumComponentsPage {
4 | createButton: ElementFinder = element(by.id('jh-create-entity'));
5 | title: ElementFinder = element(by.id('album-heading'));
6 |
7 | clickOnCreateButton() {
8 | return this.createButton.click();
9 | }
10 |
11 | getTitle() {
12 | return this.title;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/test/javascript/e2e/entities/album/album.spec.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable no-unused-expression */
2 | import { browser, protractor } from 'protractor';
3 |
4 | import NavBarPage from './../../page-objects/navbar-page';
5 | import AlbumComponentsPage from './album.page-object';
6 | import AlbumUpdatePage from './album-update.page-object';
7 |
8 | const expect = chai.expect;
9 |
10 | describe('Album e2e test', () => {
11 | let navBarPage: NavBarPage;
12 | let albumUpdatePage: AlbumUpdatePage;
13 | let albumComponentsPage: AlbumComponentsPage;
14 |
15 | before(() => {
16 | browser.get('/');
17 | navBarPage = new NavBarPage();
18 | navBarPage.getSignInPage();
19 | });
20 |
21 | it('should load Albums', async () => {
22 | navBarPage.getEntityPage('album');
23 | albumComponentsPage = new AlbumComponentsPage();
24 | expect(await albumComponentsPage.getTitle().getText()).to.match(/Albums/);
25 | });
26 |
27 | it('should load create Album page', async () => {
28 | albumComponentsPage.clickOnCreateButton();
29 | albumUpdatePage = new AlbumUpdatePage();
30 | expect(await albumUpdatePage.getPageTitle().getAttribute('id')).to.match(/galleryApp.album.home.createOrEditLabel/);
31 | });
32 |
33 | it('should create and save Albums', async () => {
34 | albumUpdatePage.setTitleInput('title');
35 | expect(await albumUpdatePage.getTitleInput()).to.match(/title/);
36 | albumUpdatePage.setDescriptionInput('description');
37 | expect(await albumUpdatePage.getDescriptionInput()).to.match(/description/);
38 | albumUpdatePage.setCreatedInput('01/01/2001' + protractor.Key.TAB + '02:30AM');
39 | expect(await albumUpdatePage.getCreatedInput()).to.contain('2001-01-01T02:30');
40 | albumUpdatePage.userSelectLastOption();
41 | await albumUpdatePage.save();
42 | expect(await albumUpdatePage.getSaveButton().isPresent()).to.be.false;
43 | });
44 |
45 | after(() => {
46 | navBarPage.autoSignOut();
47 | });
48 | });
49 |
--------------------------------------------------------------------------------
/src/test/javascript/e2e/entities/photo/photo.page-object.ts:
--------------------------------------------------------------------------------
1 | import { element, by, ElementFinder } from 'protractor';
2 |
3 | export default class PhotoComponentsPage {
4 | createButton: ElementFinder = element(by.id('jh-create-entity'));
5 | title: ElementFinder = element(by.id('photo-heading'));
6 |
7 | clickOnCreateButton() {
8 | return this.createButton.click();
9 | }
10 |
11 | getTitle() {
12 | return this.title;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/test/javascript/e2e/entities/photo/photo.spec.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable no-unused-expression */
2 | import { browser, protractor } from 'protractor';
3 |
4 | import NavBarPage from './../../page-objects/navbar-page';
5 | import PhotoComponentsPage from './photo.page-object';
6 | import PhotoUpdatePage from './photo-update.page-object';
7 | import * as path from 'path';
8 |
9 | const expect = chai.expect;
10 |
11 | describe('Photo e2e test', () => {
12 | let navBarPage: NavBarPage;
13 | let photoUpdatePage: PhotoUpdatePage;
14 | let photoComponentsPage: PhotoComponentsPage;
15 | const fileToUpload = '../../../../../main/webapp/static/images/logo-jhipster.png';
16 | const absolutePath = path.resolve(__dirname, fileToUpload);
17 |
18 | before(() => {
19 | browser.get('/');
20 | navBarPage = new NavBarPage();
21 | navBarPage.getSignInPage();
22 | });
23 |
24 | it('should load Photos', async () => {
25 | navBarPage.getEntityPage('photo');
26 | photoComponentsPage = new PhotoComponentsPage();
27 | expect(await photoComponentsPage.getTitle().getText()).to.match(/Photos/);
28 | });
29 |
30 | it('should load create Photo page', async () => {
31 | photoComponentsPage.clickOnCreateButton();
32 | photoUpdatePage = new PhotoUpdatePage();
33 | expect(await photoUpdatePage.getPageTitle().getAttribute('id')).to.match(/galleryApp.photo.home.createOrEditLabel/);
34 | });
35 |
36 | it('should create and save Photos', async () => {
37 | photoUpdatePage.setTitleInput('title');
38 | expect(await photoUpdatePage.getTitleInput()).to.match(/title/);
39 | photoUpdatePage.setDescriptionInput('description');
40 | expect(await photoUpdatePage.getDescriptionInput()).to.match(/description/);
41 | photoUpdatePage.setImageInput(absolutePath);
42 | photoUpdatePage.albumSelectLastOption();
43 | // photoUpdatePage.tagSelectLastOption();
44 | await photoUpdatePage.save();
45 | expect(await photoUpdatePage.getSaveButton().isPresent()).to.be.false;
46 | });
47 |
48 | after(() => {
49 | navBarPage.autoSignOut();
50 | });
51 | });
52 |
--------------------------------------------------------------------------------
/src/test/javascript/e2e/entities/tag/tag-update.page-object.ts:
--------------------------------------------------------------------------------
1 | import { element, by, ElementFinder } from 'protractor';
2 |
3 | export default class TagUpdatePage {
4 | pageTitle: ElementFinder = element(by.id('galleryApp.tag.home.createOrEditLabel'));
5 | saveButton: ElementFinder = element(by.id('save-entity'));
6 | cancelButton: ElementFinder = element(by.id('cancel-save'));
7 | nameInput: ElementFinder = element(by.css('input#tag-name'));
8 |
9 | getPageTitle() {
10 | return this.pageTitle;
11 | }
12 |
13 | setNameInput(name) {
14 | this.nameInput.sendKeys(name);
15 | }
16 |
17 | getNameInput() {
18 | return this.nameInput.getAttribute('value');
19 | }
20 |
21 | save() {
22 | return this.saveButton.click();
23 | }
24 |
25 | cancel() {
26 | this.cancelButton.click();
27 | }
28 |
29 | getSaveButton() {
30 | return this.saveButton;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/test/javascript/e2e/entities/tag/tag.page-object.ts:
--------------------------------------------------------------------------------
1 | import { element, by, ElementFinder } from 'protractor';
2 |
3 | export default class TagComponentsPage {
4 | createButton: ElementFinder = element(by.id('jh-create-entity'));
5 | title: ElementFinder = element(by.id('tag-heading'));
6 |
7 | clickOnCreateButton() {
8 | return this.createButton.click();
9 | }
10 |
11 | getTitle() {
12 | return this.title;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/test/javascript/e2e/entities/tag/tag.spec.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable no-unused-expression */
2 | import { browser } from 'protractor';
3 |
4 | import NavBarPage from './../../page-objects/navbar-page';
5 | import TagComponentsPage from './tag.page-object';
6 | import TagUpdatePage from './tag-update.page-object';
7 |
8 | const expect = chai.expect;
9 |
10 | describe('Tag e2e test', () => {
11 | let navBarPage: NavBarPage;
12 | let tagUpdatePage: TagUpdatePage;
13 | let tagComponentsPage: TagComponentsPage;
14 |
15 | before(() => {
16 | browser.get('/');
17 | navBarPage = new NavBarPage();
18 | navBarPage.getSignInPage();
19 | });
20 |
21 | it('should load Tags', async () => {
22 | navBarPage.getEntityPage('tag');
23 | tagComponentsPage = new TagComponentsPage();
24 | expect(await tagComponentsPage.getTitle().getText()).to.match(/Tags/);
25 | });
26 |
27 | it('should load create Tag page', async () => {
28 | tagComponentsPage.clickOnCreateButton();
29 | tagUpdatePage = new TagUpdatePage();
30 | expect(await tagUpdatePage.getPageTitle().getAttribute('id')).to.match(/galleryApp.tag.home.createOrEditLabel/);
31 | });
32 |
33 | it('should create and save Tags', async () => {
34 | tagUpdatePage.setNameInput('name');
35 | expect(await tagUpdatePage.getNameInput()).to.match(/name/);
36 | await tagUpdatePage.save();
37 | expect(await tagUpdatePage.getSaveButton().isPresent()).to.be.false;
38 | });
39 |
40 | after(() => {
41 | navBarPage.autoSignOut();
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/src/test/javascript/e2e/modules/account/account.spec.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable no-unused-expression */
2 | import { browser, element, by } from 'protractor';
3 |
4 | import SignInPage from '../../page-objects/signin-page';
5 | import NavBarPage from '../../page-objects/navbar-page';
6 | import { waitUntilDisplayed } from '../../util/utils';
7 |
8 | const expect = chai.expect;
9 |
10 | describe('Account', () => {
11 | let navBarPage: NavBarPage;
12 | let signInPage: SignInPage;
13 | const loginPageTitle = 'login-title';
14 |
15 | before(() => {
16 | browser.get('/');
17 | navBarPage = new NavBarPage(true);
18 | signInPage = navBarPage.getSignInPage();
19 | });
20 |
21 | it('should fail to login with bad password', async () => {
22 | signInPage.loginWithOAuth('admin', 'foo');
23 | const alert = element(by.css('.alert-error'));
24 | if (await alert.isPresent()) {
25 | // Keycloak
26 | expect(await alert.getText()).to.eq('Invalid username or password.');
27 | } else {
28 | // Okta
29 | const error = element(by.css('.infobox-error'));
30 | waitUntilDisplayed(error);
31 | expect(await error.getText()).to.eq('Sign in failed!');
32 | }
33 | await signInPage.clearUserName();
34 | await signInPage.clearPassword();
35 | });
36 |
37 | it('should login with admin account', async () => {
38 | browser.get('/');
39 | signInPage = navBarPage.getSignInPage();
40 | // Keycloak credentials by default, change them to be able to use oauth2 with Okta
41 | signInPage.loginWithOAuth('admin', 'admin');
42 | const success = element(by.className('alert-success'));
43 | waitUntilDisplayed(success);
44 | // Success alert should appear in home page
45 | expect(await success.isPresent()).to.be.true;
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/src/test/javascript/e2e/modules/administration/administration.spec.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable no-unused-expression */
2 | import { element, by, browser } from 'protractor';
3 |
4 | import NavBarPage from '../../page-objects/navbar-page';
5 |
6 | const expect = chai.expect;
7 |
8 | describe('Administration', () => {
9 | let navBarPage: NavBarPage;
10 |
11 | before(() => {
12 | browser.get('/');
13 | navBarPage = new NavBarPage(true);
14 | });
15 |
16 | it('should load metrics', async () => {
17 | navBarPage.clickOnAdminMenuItem('metrics');
18 | expect(await element(by.className('metrics-page-heading')).getText()).to.eq('Application Metrics');
19 | });
20 |
21 | it('should load health', async () => {
22 | navBarPage.clickOnAdminMenuItem('health');
23 | expect(await element(by.className('health-page-heading')).getText()).to.eq('Health Checks');
24 | });
25 |
26 | it('should load configuration', async () => {
27 | navBarPage.clickOnAdminMenuItem('configuration');
28 | expect(await element(by.className('configuration-page-heading')).getText()).to.eq('Configuration');
29 | });
30 |
31 | it('should load audits', async () => {
32 | navBarPage.clickOnAdminMenuItem('audits');
33 | expect(await element(by.className('audits-page-heading')).getText()).to.eq('Audits');
34 | });
35 |
36 | it('should load logs', async () => {
37 | navBarPage.clickOnAdminMenuItem('logs');
38 | expect(await element(by.className('logs-page-heading')).getText()).to.eq('Logs');
39 | });
40 |
41 | after(() => navBarPage.autoSignOut());
42 | });
43 |
--------------------------------------------------------------------------------
/src/test/javascript/e2e/page-objects/base-component.ts:
--------------------------------------------------------------------------------
1 | import { ElementFinder } from 'protractor';
2 |
3 | import { isDisplayed, isHidden, waitUntilDisplayed, waitUntilHidden } from '../util/utils';
4 | /**
5 | * Base ui component class that other components should inherit from.
6 | */
7 | export default class BasePage {
8 | /**
9 | * This class property enables use of specific functions 'isDisplayed' and 'waitUntilDisplayed'
10 | */
11 | selector: ElementFinder = undefined;
12 |
13 | constructor(selector?) {
14 | this.selector = selector;
15 | }
16 |
17 | checkSelectorExist() {
18 | if (this.selector === undefined) {
19 | throw new TypeError(
20 | `Class '${this.constructor.name}' ` +
21 | `extends 'UIComponent' possibly 'Page' Object Class and have to implement abstract property 'selector' ` +
22 | `when 'isDisplayed' or 'waitUntilDisplayed' are used`
23 | );
24 | }
25 | }
26 |
27 | /**
28 | * @returns Function which resolves to boolean
29 | */
30 | isDisplayed() {
31 | this.checkSelectorExist();
32 | return isDisplayed(this.selector);
33 | }
34 |
35 | isHidden() {
36 | this.checkSelectorExist();
37 | return isHidden(this.selector);
38 | }
39 |
40 | /**
41 | * Wait until this page is displayed.
42 | */
43 | waitUntilDisplayed() {
44 | this.checkSelectorExist();
45 | waitUntilDisplayed(this.selector, this.constructor.name);
46 | }
47 |
48 | waitUntilHidden() {
49 | this.checkSelectorExist();
50 | waitUntilHidden(this.selector, this.constructor.name);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/test/javascript/e2e/page-objects/navbar-page.ts:
--------------------------------------------------------------------------------
1 | import { $, ElementFinder } from 'protractor';
2 |
3 | import BasePage from './base-component';
4 | import SignInPage from './signin-page';
5 |
6 | const selector: ElementFinder = $('#app-header');
7 | export default class NavBarPage extends BasePage {
8 | selector: ElementFinder;
9 | signInPage: SignInPage;
10 | adminMenu: ElementFinder;
11 | accountMenu: ElementFinder = this.selector.$('#account-menu');
12 | entityMenu: ElementFinder = this.selector.$('#entity-menu');
13 | loginItem: ElementFinder = this.selector.$('#login-item');
14 |
15 | constructor(asAdmin?: Boolean) {
16 | super(selector);
17 | this.selector = selector;
18 | if (asAdmin) {
19 | this.adminMenu = this.selector.$('#admin-menu');
20 | }
21 | this.signInPage = new SignInPage();
22 | }
23 |
24 | getSignInPage() {
25 | this.clickOnAccountMenu();
26 | this.loginItem.click();
27 | return new SignInPage();
28 | }
29 |
30 | getEntityPage(entityName: string) {
31 | this.clickOnEntityMenu();
32 | return this.clickOnEntity(entityName);
33 | }
34 |
35 | clickOnTabMenu(item: string) {
36 | return this.selector
37 | .$('#header-tabs')
38 | .$(`.dropdown-item[href="${item}"]`)
39 | .click();
40 | }
41 |
42 | clickOnAccountMenu() {
43 | return this.accountMenu.click();
44 | }
45 |
46 | clickOnAccountMenuItem(item: string) {
47 | this.accountMenu.click();
48 | return this.selector.$(`.dropdown-item[href="#/account/${item}"`).click();
49 | }
50 |
51 | clickOnAdminMenuItem(item: string) {
52 | this.adminMenu.click();
53 | return this.selector.$(`.dropdown-item[href="#/admin/${item}"]`).click();
54 | }
55 |
56 | clickOnEntityMenu() {
57 | return this.entityMenu.click();
58 | }
59 |
60 | clickOnEntity(entityName: string) {
61 | return this.selector.$(`.dropdown-item[href="#/entity/${entityName}"]`).click();
62 | }
63 |
64 | autoSignIn() {
65 | this.signInPage.get();
66 | this.signInPage.loginWithOAuth('admin', 'admin');
67 | return this.signInPage.waitUntilHidden();
68 | }
69 |
70 | autoSignOut() {
71 | this.signInPage.autoSignOut();
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/test/javascript/e2e/page-objects/signin-page.ts:
--------------------------------------------------------------------------------
1 | import { $, browser, ElementFinder, element, by } from 'protractor';
2 |
3 | import BasePage from './base-component';
4 |
5 | const selector: ElementFinder = $('#login-page');
6 | export default class SignInPage extends BasePage {
7 | selector: ElementFinder;
8 | username: ElementFinder = element(by.name('username'));
9 | password: ElementFinder = element(by.name('password'));
10 | loginButton: ElementFinder = element(by.css('input[type=submit]'));
11 | title: ElementFinder = this.selector.$('#login-title');
12 |
13 | constructor() {
14 | super(selector);
15 | this.selector = selector;
16 | }
17 |
18 | get() {
19 | browser.get('#/login');
20 | this.waitUntilDisplayed();
21 | }
22 |
23 | getTitle() {
24 | return this.title.getAttribute('id');
25 | }
26 |
27 | setUserName(username: string) {
28 | return this.username.sendKeys(username);
29 | }
30 |
31 | clearUserName() {
32 | return this.username.clear();
33 | }
34 |
35 | setPassword(password: string) {
36 | return this.password.sendKeys(password);
37 | }
38 |
39 | clearPassword() {
40 | return this.password.clear();
41 | }
42 |
43 | loginWithOAuth(username: string, password: string) {
44 | this.username.isPresent().then(() => {
45 | this.setUserName(username);
46 | this.setPassword(password);
47 | return this.login();
48 | });
49 | }
50 |
51 | autoSignOut = () => browser.get('#/logout');
52 |
53 | login() {
54 | return this.loginButton.click();
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/test/javascript/e2e/util/utils.ts:
--------------------------------------------------------------------------------
1 | import { ExpectedConditions, ElementFinder, browser, by, element } from 'protractor';
2 |
3 | const waitUntilDisplayedTimeout = 30000;
4 |
5 | export const checkSelectorExist = (selector: ElementFinder) => selector !== undefined;
6 |
7 | /**
8 | * @returns Function which resolves to boolean
9 | */
10 | export const isDisplayed = (selector: ElementFinder) => {
11 | if (!checkSelectorExist(selector)) return;
12 | return ExpectedConditions.visibilityOf(selector);
13 | };
14 |
15 | export const isHidden = (selector: ElementFinder) => {
16 | if (!checkSelectorExist(selector)) return;
17 | return ExpectedConditions.invisibilityOf(selector);
18 | };
19 |
20 | /**
21 | * Wait until this page is displayed.
22 | */
23 | export const waitUntilDisplayed = (selector: ElementFinder, classname = '', timeout = waitUntilDisplayedTimeout) => {
24 | if (!checkSelectorExist(selector)) return;
25 |
26 | browser.wait(
27 | isDisplayed(selector),
28 | timeout,
29 | `Failed while waiting for "${selector.locator()}" of Page Object Class '${classname}' to display.`
30 | );
31 | };
32 |
33 | export const waitUntilHidden = (selector: ElementFinder, classname = '', timeout = waitUntilDisplayedTimeout) => {
34 | if (!checkSelectorExist(selector)) return;
35 |
36 | browser.wait(
37 | isHidden(selector),
38 | timeout,
39 | `Failed while waiting for "${selector.locator()}" of Page Object Class '${classname}' to be hidden.`
40 | );
41 | };
42 |
43 | export const getUserDeactivatedButtonByLogin = (login: string): ElementFinder =>
44 | element(by.css('table > tbody'))
45 | .element(by.id(login))
46 | .element(by.buttonText('Deactivated'));
47 |
48 | export const getToastByInnerText = (text: string): ElementFinder =>
49 | element(by.css('.toastify-container')).element(by.cssContainingText('div[role=alert]', text));
50 |
--------------------------------------------------------------------------------
/src/test/javascript/enzyme-setup.ts:
--------------------------------------------------------------------------------
1 | import { configure } from 'enzyme';
2 | import Adapter from 'enzyme-adapter-react-16';
3 |
4 | // React 16 Enzyme adapter
5 | configure({ adapter: new Adapter() });
6 |
--------------------------------------------------------------------------------
/src/test/javascript/jest.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | transform: {
3 | '^.+\\.tsx?$': 'ts-jest'
4 | },
5 | coverageDirectory: '/target/test-results/',
6 | rootDir: '../../../',
7 | testMatch: ['/src/test/javascript/spec/**/+(*.)+(spec.ts?(x))'],
8 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
9 | moduleNameMapper: {
10 | 'app/(.*)': '/src/main/webapp/app/$1',
11 | '\\.(css|scss)$': 'identity-obj-proxy'
12 | },
13 | reporters: [
14 | 'default'
15 | ],
16 | testResultsProcessor: 'jest-sonar-reporter',
17 | testPathIgnorePatterns: [
18 | '/node_modules/',
19 | '/src/test/javascript/spec/app/modules/account/sessions/sessions.reducer.spec.ts'
20 | ],
21 | setupFiles: [
22 | '/src/test/javascript/enzyme-setup.ts',
23 | '/src/test/javascript/storage-mock.ts'
24 | ]
25 | };
26 |
--------------------------------------------------------------------------------
/src/test/javascript/protractor.conf.js:
--------------------------------------------------------------------------------
1 | const os = require('os');
2 |
3 | exports.config = {
4 | allScriptsTimeout: 20000,
5 |
6 | specs: [
7 | './e2e/modules/account/*.spec.ts',
8 | './e2e/modules/administration/*.spec.ts',
9 | './e2e/entities/**/*.spec.ts'
10 | /* jhipster-needle-add-protractor-tests - JHipster will add protractors tests here */
11 | ],
12 |
13 | capabilities: {
14 | browserName: 'chrome',
15 | chromeOptions: {
16 | args: [ '--disable-gpu', '--window-size=800,600' ]
17 | }
18 | },
19 |
20 | directConnect: true,
21 |
22 | baseUrl: 'http://localhost:8080/',
23 |
24 | framework: 'mocha',
25 |
26 | mochaOpts: {
27 | reporter: 'spec',
28 | slow: 3000,
29 | ui: 'bdd',
30 | timeout: 30000
31 | },
32 |
33 | beforeLaunch () {
34 | require('ts-node').register({
35 | project: 'src/test/javascript/tsconfig.e2e.json'
36 | });
37 | },
38 |
39 | onPrepare () {
40 | // @ts-ignore
41 | browser.driver.manage().window().setSize(1280, 1024);
42 | // @ts-ignore
43 | browser.ignoreSynchronization = true;
44 | // Disable animations
45 | // @ts-ignore
46 | browser.executeScript('document.body.className += " notransition";');
47 | const chai = require('chai');
48 | const chaiAsPromised = require('chai-as-promised');
49 | chai.use(chaiAsPromised);
50 | // @ts-ignore
51 | global.chai = chai;
52 | }
53 | };
54 |
--------------------------------------------------------------------------------
/src/test/javascript/spec/app/config/notification-middleware.spec.ts:
--------------------------------------------------------------------------------
1 | import { createStore, applyMiddleware } from 'redux';
2 | import promiseMiddleware from 'redux-promise-middleware';
3 | // import * as toaster from 'react-toastify';
4 | // import * as sinon from 'sinon';
5 |
6 | import notificationMiddleware from 'app/config/notification-middleware';
7 |
8 | describe('Notification Middleware', () => {
9 | let store;
10 |
11 | const SUCCESS_TYPE = 'SUCCESS';
12 | const ERROR_TYPE = 'SUCCESS';
13 | const DEFAULT_SUCCESS_MESSAGE = 'fooSuccess';
14 | const DEFAULT_ERROR_MESSAGE = 'fooError';
15 |
16 | // Default action for use in local tests
17 | const DEFAULT = {
18 | type: SUCCESS_TYPE,
19 | payload: 'foo'
20 | };
21 | const DEFAULT_PROMISE = {
22 | type: SUCCESS_TYPE,
23 | payload: Promise.resolve('foo')
24 | };
25 | const DEFAULT_SUCCESS = {
26 | type: SUCCESS_TYPE,
27 | meta: {
28 | successMessage: DEFAULT_SUCCESS_MESSAGE
29 | },
30 | payload: Promise.resolve('foo')
31 | };
32 | const DEFAULT_ERROR = {
33 | type: ERROR_TYPE,
34 | meta: {
35 | errorMessage: DEFAULT_ERROR_MESSAGE
36 | },
37 | payload: Promise.reject(new Error('foo'))
38 | };
39 |
40 | const makeStore = () => applyMiddleware(notificationMiddleware, promiseMiddleware())(createStore)(() => null);
41 |
42 | beforeEach(() => {
43 | store = makeStore();
44 | // sinon.spy(toaster, 'toast');
45 | });
46 |
47 | afterEach(() => {
48 | // toaster.toast.restore();
49 | });
50 |
51 | it('should not trigger a toast message but should return action', () => {
52 | expect(store.dispatch(DEFAULT).payload).toEqual('foo');
53 | // expect(toaster.toast.called).toEqual(false);
54 | });
55 |
56 | it('should not trigger a toast message but should return promise success', async () => {
57 | await store.dispatch(DEFAULT_PROMISE).then(resp => {
58 | expect(resp.value).toEqual('foo');
59 | });
60 | // expect(toaster.toast.called).toEqual(false);
61 | });
62 |
63 | it('should trigger a success toast message and return promise success', async () => {
64 | await store.dispatch(DEFAULT_SUCCESS).then(resp => {
65 | expect(resp.value).toEqual('foo');
66 | });
67 | // expect(toaster.toast.getCall(0).args[0]).toEqual(DEFAULT_SUCCESS_MESSAGE);
68 | });
69 |
70 | it('should trigger an error toast message and return promise error', async () => {
71 | await store.dispatch(DEFAULT_ERROR).catch(err => {
72 | expect(err.message).toEqual('foo');
73 | });
74 | // expect(toaster.toast.getCall(0).args[0]).toEqual(DEFAULT_ERROR_MESSAGE);
75 | });
76 | });
77 |
--------------------------------------------------------------------------------
/src/test/javascript/spec/app/shared/error/error-boundary-route.spec.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Route } from 'react-router-dom';
3 | import { shallow, mount } from 'enzyme';
4 |
5 | import ErrorBoundaryRoute from 'app/shared/error/error-boundary-route';
6 |
7 | const ErrorComp = () => {
8 | throw new Error('test');
9 | };
10 |
11 | describe('error-boundary-route component', () => {
12 | beforeEach(() => {
13 | // ignore console and jsdom errors
14 | jest.spyOn(window._virtualConsole, 'emit').mockImplementation(() => false);
15 | jest.spyOn(global.console, 'error').mockImplementation(() => false);
16 | });
17 |
18 | // All tests will go here
19 | it('Should throw error when no component is provided', () => {
20 | expect(() => shallow()).toThrow(Error);
21 | });
22 |
23 | it('Should render fallback component when an uncaught error is thrown from component', () => {
24 | const route = shallow();
25 | const renderedRoute = route.find(Route);
26 | expect(renderedRoute.length).toEqual(1);
27 | expect(renderedRoute.props().path).toEqual('/');
28 | expect(renderedRoute.props().render).toBeDefined();
29 | const renderFn: Function = renderedRoute.props().render;
30 | const comp = mount(
31 | renderFn({
32 | location: '/'
33 | })
34 | );
35 | expect(comp.length).toEqual(1);
36 | expect(comp.html()).toEqual('An unexpected error has occurred.
');
37 | });
38 | });
39 |
--------------------------------------------------------------------------------
/src/test/javascript/spec/app/shared/error/error-boundary.spec.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { shallow, mount } from 'enzyme';
3 |
4 | import ErrorBoundary from 'app/shared/error/error-boundary';
5 |
6 | const ErrorComp = () => {
7 | throw new Error('test');
8 | };
9 |
10 | describe('error component', () => {
11 | beforeEach(() => {
12 | // ignore console and jsdom errors
13 | jest.spyOn(window._virtualConsole, 'emit').mockImplementation(() => false);
14 | jest.spyOn(global.console, 'error').mockImplementation(() => false);
15 | });
16 |
17 | it('Should throw an error when componnet is not enclosed in Error Boundary', () => {
18 | expect(() => shallow()).toThrow(Error);
19 | });
20 |
21 | it('Should call Error Boundary componentDidCatch method', () => {
22 | const spy = jest.spyOn(ErrorBoundary.prototype, 'componentDidCatch');
23 | mount(
24 |
25 |
26 |
27 | );
28 | expect(spy).toHaveBeenCalled();
29 | });
30 | });
31 |
--------------------------------------------------------------------------------
/src/test/javascript/spec/app/shared/layout/header/menus/account.spec.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { shallow } from 'enzyme';
3 |
4 | import { getLoginUrl } from 'app/shared/util/url-utils';
5 | import { NavDropdown } from 'app/shared/layout/header/header-components';
6 | import { AccountMenu } from 'app/shared/layout/header/menus';
7 |
8 | describe('AccountMenu', () => {
9 | let mountedWrapper;
10 |
11 | const authenticatedWrapper = () => {
12 | if (!mountedWrapper) {
13 | mountedWrapper = shallow();
14 | }
15 | return mountedWrapper;
16 | };
17 | const guestWrapper = () => {
18 | if (!mountedWrapper) {
19 | mountedWrapper = shallow();
20 | }
21 | return mountedWrapper;
22 | };
23 |
24 | beforeEach(() => {
25 | mountedWrapper = undefined;
26 | });
27 |
28 | // All tests will go here
29 |
30 | it('Renders a authenticated AccountMenu component', () => {
31 | const dropdown = authenticatedWrapper().find(NavDropdown);
32 | expect(dropdown).toHaveLength(1);
33 | expect(dropdown.find({ to: '/login' })).toHaveLength(0);
34 | expect(dropdown.find({ to: '/logout' })).toHaveLength(1);
35 | });
36 |
37 | it('Renders a guest AccountMenu component', () => {
38 | const dropdown = guestWrapper().find(NavDropdown);
39 | expect(dropdown).toHaveLength(1);
40 | expect(dropdown.find({ href: getLoginUrl() })).toHaveLength(1);
41 | expect(dropdown.find({ to: '/logout' })).toHaveLength(0);
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/src/test/javascript/spec/app/shared/util/entity-utils.spec.ts:
--------------------------------------------------------------------------------
1 | import { cleanEntity } from 'app/shared/util/entity-utils';
2 |
3 | describe('Entity utils', () => {
4 | describe('cleanEntity', () => {
5 | it('should not remove fields with an id', () => {
6 | const entityA = {
7 | a: {
8 | id: 5
9 | }
10 | };
11 | const entityB = {
12 | a: {
13 | id: '5'
14 | }
15 | };
16 |
17 | expect(cleanEntity({ ...entityA })).toEqual(entityA);
18 | expect(cleanEntity({ ...entityB })).toEqual(entityB);
19 | });
20 |
21 | it('should remove fields with an empty id', () => {
22 | const entity = {
23 | a: {
24 | id: ''
25 | }
26 | };
27 |
28 | expect(cleanEntity({ ...entity })).toEqual({});
29 | });
30 |
31 | it('should not remove fields that are not objects', () => {
32 | const entity = {
33 | a: '',
34 | b: 5,
35 | c: [],
36 | d: '5'
37 | };
38 |
39 | expect(cleanEntity({ ...entity })).toEqual(entity);
40 | });
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/src/test/javascript/spec/app/utils.ts:
--------------------------------------------------------------------------------
1 | // A dirty way to remove functions and undefined from an object for comparison
2 | export const cleanupObj = obj => JSON.parse(JSON.stringify(obj));
3 |
--------------------------------------------------------------------------------
/src/test/javascript/storage-mock.ts:
--------------------------------------------------------------------------------
1 | let StorageMock = () => {
2 | let store = {};
3 | return {
4 | getItem: (key: any) => store[key] || null,
5 | setItem: (key: any, value: any) => (store[key] = value.toString()),
6 | clear: () => (store = {})
7 | };
8 | };
9 |
10 | Object.defineProperty(window, 'localStorage', {
11 | value: StorageMock()
12 | });
13 |
14 | Object.defineProperty(window, 'sessionStorage', {
15 | value: StorageMock()
16 | });
17 |
--------------------------------------------------------------------------------
/src/test/javascript/tsconfig.e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../../tsconfig.json",
3 | "compilerOptions": {
4 | "types": [
5 | "chai",
6 | "mocha"
7 | ]
8 | },
9 | "include": [
10 | "src/main/webapp/app/typing.d.ts",
11 | "src/main/webapp/app/**/*",
12 | "src/test/javascript/**/*"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/src/test/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "jsx": "react",
4 | "target": "es5",
5 | "module": "commonjs",
6 | "moduleResolution": "node",
7 | "sourceMap": true,
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "removeComments": false,
11 | "noImplicitAny": false,
12 | "suppressImplicitAnyIndexErrors": true,
13 | "allowSyntheticDefaultImports": true,
14 | "outDir": "target/www/app",
15 | "lib": ["es2015", "es2017", "dom"],
16 | "typeRoots": [
17 | "node_modules/@types"
18 | ],
19 | "types": ["webpack-env"],
20 | "allowJs": true,
21 | "checkJs": false,
22 | "baseUrl": "./",
23 | "paths": {
24 | "app/*": ["src/main/webapp/app/*"]
25 | },
26 | "importHelpers": true
27 | },
28 | "include": [
29 | "src/main/webapp/app/typing.d.ts",
30 | "src/main/webapp/app/**/*"
31 | ],
32 | "exclude": [
33 | "node_modules"
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/webpack/utils.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 |
4 | module.exports = {
5 | parseVersion,
6 | root,
7 | isExternalLib
8 | };
9 |
10 | const parseString = require('xml2js').parseString;
11 | // return the version number from `pom.xml` file
12 | function parseVersion() {
13 | let version = null;
14 | const pomXml = fs.readFileSync('pom.xml', 'utf8');
15 | parseString(pomXml, (err, result) => {
16 | if (result.project.version && result.project.version[0]) {
17 | version = result.project.version[0];
18 | } else if (result.project.parent && result.project.parent[0] && result.project.parent[0].version && result.project.parent[0].version[0]) {
19 | version = result.project.parent[0].version[0];
20 | }
21 | });
22 | if (version === null) {
23 | throw new Error('pom.xml is malformed. No version is defined');
24 | }
25 | return version;
26 | }
27 |
28 | const _root = path.resolve(__dirname, '..');
29 |
30 | function root(args) {
31 | args = Array.prototype.slice.call(arguments, 0);
32 | return path.join.apply(path, [_root].concat(args));
33 | }
34 |
35 | function isExternalLib(module, check = /node_modules/) {
36 | const req = module.userRequest;
37 | if (typeof req !== 'string') {
38 | return false;
39 | }
40 | return req.search(check) >= 0;
41 | }
42 |
--------------------------------------------------------------------------------
/webpack/webpack.dev.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const writeFilePlugin = require('write-file-webpack-plugin');
3 | const webpackMerge = require('webpack-merge');
4 | const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
5 | const WebpackNotifierPlugin = require('webpack-notifier');
6 | const path = require('path');
7 |
8 | const utils = require('./utils.js');
9 | const commonConfig = require('./webpack.common.js');
10 |
11 | const ENV = 'development';
12 |
13 | module.exports = webpackMerge(commonConfig({ env: ENV }), {
14 | devtool: 'cheap-module-source-map', // https://reactjs.org/docs/cross-origin-errors.html
15 | mode: 'development',
16 | entry: [
17 | 'react-hot-loader/patch',
18 | './src/main/webapp/app/index'
19 | ],
20 | output: {
21 | path: utils.root('target/www'),
22 | filename: 'app/[name].bundle.js',
23 | chunkFilename: 'app/[id].chunk.js'
24 | },
25 | module: {
26 | rules: [
27 | {
28 | test: /\.scss$/,
29 | loaders: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader']
30 | },
31 | {
32 | test: /\.css$/,
33 | loaders: ['style-loader', 'css-loader']
34 | }
35 | ]
36 | },
37 | devServer: {
38 | stats: {
39 | children: false
40 | },
41 | hot: true,
42 | contentBase: './target/www',
43 | proxy: [{
44 | context: [
45 | /* jhipster-needle-add-entity-to-webpack - JHipster will add entity api paths here */
46 | '/api',
47 | '/management',
48 | '/swagger-resources',
49 | '/v2/api-docs',
50 | '/h2-console',
51 | '/auth'
52 | ],
53 | target: 'http://127.0.0.1:8080',
54 | secure: false,
55 | headers: { host: 'localhost:9000' }
56 | }],
57 | watchOptions: {
58 | ignored: /node_modules/
59 | }
60 | },
61 | plugins: [
62 | new BrowserSyncPlugin({
63 | host: 'localhost',
64 | port: 9000,
65 | proxy: {
66 | target: 'http://localhost:9060'
67 | }
68 | }, {
69 | reload: false
70 | }),
71 | new webpack.HotModuleReplacementPlugin(),
72 | new writeFilePlugin(),
73 | new webpack.WatchIgnorePlugin([
74 | utils.root('src/test'),
75 | ]),
76 | new WebpackNotifierPlugin({
77 | title: 'JHipster',
78 | contentImage: path.join(__dirname, 'logo-jhipster.png')
79 | })
80 | ]
81 | });
82 |
--------------------------------------------------------------------------------