├── .gitignore ├── README.md ├── chatdv-backend ├── .gitignore ├── .mvn │ └── wrapper │ │ └── maven-wrapper.properties ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── dev │ │ │ └── danvega │ │ │ ├── Application.java │ │ │ └── ChatController.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── dev │ └── danvega │ └── ApplicationTests.java ├── chatdv-frontend ├── .gitignore ├── README.md ├── index.html ├── main.js ├── package-lock.json ├── package.json └── public │ └── vite.svg ├── chatdv-htmx ├── .gitignore ├── .mvn │ └── wrapper │ │ └── maven-wrapper.properties ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── dev │ │ │ └── danvega │ │ │ └── chatdv_htmx │ │ │ ├── Application.java │ │ │ └── ChatController.java │ └── resources │ │ ├── application.properties │ │ └── templates │ │ ├── chat-form.html │ │ ├── index.html │ │ ├── response.html │ │ └── todays-message-list.html │ └── test │ └── java │ └── dev │ └── danvega │ └── chatdv_htmx │ └── ChatdvHtmxApplicationTests.java ├── full-stack-spring-vue ├── .gitignore ├── .mvn │ └── wrapper │ │ └── maven-wrapper.properties ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml ├── run.sh └── src │ ├── frontend │ ├── .env │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── App.vue │ │ ├── assets │ │ │ └── vue.svg │ │ ├── components │ │ │ └── HelloWorld.vue │ │ ├── main.js │ │ └── style.css │ └── vite.config.js │ ├── main │ ├── java │ │ └── dev │ │ │ └── danvega │ │ │ ├── Application.java │ │ │ └── MessageController.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── dev │ └── danvega │ └── FullStuckSpringVueApplicationTests.java ├── spring-mvc-sessions ├── .gitignore ├── .mvn │ └── wrapper │ │ └── maven-wrapper.properties ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── dev │ │ │ └── danvega │ │ │ └── conference │ │ │ ├── Application.java │ │ │ └── session │ │ │ ├── Session.java │ │ │ ├── SessionApiController.java │ │ │ ├── SessionController.java │ │ │ ├── SessionRepository.java │ │ │ └── Sessions.java │ ├── jte │ │ ├── .jteroot │ │ └── index.jte │ └── resources │ │ ├── application.properties │ │ └── data │ │ └── sessions.json │ └── test │ └── java │ └── dev │ └── danvega │ └── conference │ └── SessionsApplicationTests.java ├── vaadin-sessions ├── .gitignore ├── .idea │ ├── .gitignore │ ├── compiler.xml │ ├── encodings.xml │ ├── jarRepositories.xml │ ├── misc.xml │ └── vcs.xml ├── README.md ├── frontend │ ├── generated │ │ ├── flow │ │ │ ├── generated-flow-imports.d.ts │ │ │ ├── generated-flow-imports.js │ │ │ └── generated-flow-webcomponent-imports.js │ │ ├── jar-resources │ │ │ ├── Flow.d.ts │ │ │ ├── Flow.js │ │ │ ├── Flow.js.map │ │ │ ├── FlowBootstrap.d.ts │ │ │ ├── FlowBootstrap.js │ │ │ ├── FlowClient.d.ts │ │ │ ├── FlowClient.js │ │ │ ├── ReactRouterOutletElement.tsx │ │ │ ├── comboBoxConnector.js │ │ │ ├── contextMenuConnector.js │ │ │ ├── contextMenuTargetConnector.js │ │ │ ├── copilot.css │ │ │ ├── copilot.js │ │ │ ├── copilot │ │ │ │ ├── base-panel-C9ezFash.js │ │ │ │ ├── copilot-B_g-uHXF.js │ │ │ │ ├── copilot-features-plugin-CcvV6-I_.js │ │ │ │ ├── copilot-feedback-plugin-12oqPZXN.js │ │ │ │ ├── copilot-global-vars-later-xOizlHDc.js │ │ │ │ ├── copilot-info-plugin-rKIOn1Z9.js │ │ │ │ ├── copilot-init-step2-xsSflCuY.js │ │ │ │ ├── copilot-log-plugin-BMXHgC_K.js │ │ │ │ ├── copilot-shortcuts-plugin-B1zChRPf.js │ │ │ │ ├── early-project-state-CqEloDes.js │ │ │ │ ├── icons-x5khyqlC.js │ │ │ │ ├── overlay-monkeypatch-CfGi1TGf.js │ │ │ │ └── state-DDML0umE.js │ │ │ ├── datepickerConnector.js │ │ │ ├── disableOnClickFunctions.js │ │ │ ├── dndConnector.js │ │ │ ├── flow-component-directive.js │ │ │ ├── flow-component-renderer.js │ │ │ ├── gridConnector.ts │ │ │ ├── index.d.ts │ │ │ ├── index.js │ │ │ ├── index.js.map │ │ │ ├── lit-renderer.ts │ │ │ ├── menubarConnector.js │ │ │ ├── messageListConnector.js │ │ │ ├── selectConnector.js │ │ │ ├── theme-util.js │ │ │ ├── tooltip.ts │ │ │ ├── vaadin-big-decimal-field.js │ │ │ ├── vaadin-dev-tools │ │ │ │ ├── License.d.ts │ │ │ │ ├── connection.d.ts │ │ │ │ ├── live-reload-connection.d.ts │ │ │ │ ├── vaadin-dev-tools.d.ts │ │ │ │ ├── vaadin-dev-tools.js │ │ │ │ └── websocket-connection.d.ts │ │ │ ├── vaadin-grid-flow-selection-column.js │ │ │ ├── vaadin-popover │ │ │ │ └── popover.ts │ │ │ ├── vaadin-time-picker │ │ │ │ ├── helpers.js │ │ │ │ └── timepickerConnector.js │ │ │ └── virtualListConnector.js │ │ ├── vaadin-featureflags.js │ │ └── vaadin.ts │ └── index.html ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── dev │ │ │ └── danvega │ │ │ └── vaadin_sessions │ │ │ ├── Application.java │ │ │ ├── Session.java │ │ │ ├── SessionRepository.java │ │ │ ├── SessionView.java │ │ │ └── Sessions.java │ └── resources │ │ ├── application.properties │ │ └── data │ │ └── sessions.json │ └── test │ └── java │ └── dev │ └── danvega │ └── vaadin_sessions │ └── VaadinSessionsApplicationTests.java └── vue-sessions ├── .env ├── .gitignore ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── postcss.config.js ├── public └── vite.svg ├── src ├── App.vue ├── assets │ └── vue.svg ├── components │ └── HelloWorld.vue ├── main.js └── style.css ├── tailwind.config.js └── vite.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | 35 | .DS_Store 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Java Developers Guide to Navigating the Frontend Landscape 2 | 3 | This is a beginner-friendly session designed for Java developers who are trying to navigate the landscape of frontend development. When you need to develop a new frontend for your application, what approach do you take? Do you leverage your existing Java skills and create it using a Java framework? Or do you opt for a modern JavaScript framework like React, Angular, or Vue? Different requirements may call for different solutions, and in this session, we will explore this topic in depth. By the end of this talk, you will be up to date with the latest techniques for building frontend applications. 4 | 5 | ## Requirements 6 | 7 | To run the projects in this repository, you'll need: 8 | - Java 17 or higher 9 | - Node.js 16 or higher 10 | - Maven 11 | - Your favorite IDE (IntelliJ IDEA, VS Code, Eclipse, etc.) 12 | 13 | ## Project Overview 14 | 15 | This repository contains several example projects that demonstrate different approaches to frontend development for Java developers: 16 | 17 | ### chatdv-backend 18 | A Spring Boot backend that provides REST APIs for the frontend demos to consume. 19 | 20 | ### chatdv-frontend 21 | A pure JavaScript/Vue.js frontend implementation that communicates with the backend API. 22 | 23 | ### chatdv-htmx 24 | A server-side rendered application using Spring Boot with HTMX for enhanced interactivity. 25 | 26 | ### full-stack-spring-vue 27 | A complete full-stack application that combines Spring Boot and Vue.js in a single deployable package. 28 | 29 | ### spring-mvc-sessions 30 | A traditional Spring MVC application with server-side rendered views using JTE templates. 31 | 32 | ### vaadin-sessions 33 | A frontend implementation using Vaadin, a Java framework for building web applications without writing HTML or JavaScript. 34 | 35 | ### vue-sessions 36 | A modern frontend implementation using Vue.js with Tailwind CSS for styling. 37 | 38 | Each project demonstrates a different approach to building frontend applications, allowing you to compare and choose the best option based on your project requirements, team expertise, and personal preferences. 39 | -------------------------------------------------------------------------------- /chatdv-backend/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /chatdv-backend/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | wrapperVersion=3.3.1 18 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip 19 | -------------------------------------------------------------------------------- /chatdv-backend/README.md: -------------------------------------------------------------------------------- 1 | # ChatDV Backend 2 | 3 | This is the backend Spring Boot project that uses Spring AI to make calls to Open AI. To run this project locally 4 | you will need an Open AI API key and you will want to update `application.properties` 5 | 6 | ```properties 7 | spring.ai.openai.api-key=${OPENAI_API_KEY} 8 | spring.ai.openai.chat.options.model=gpt-4o 9 | ``` -------------------------------------------------------------------------------- /chatdv-backend/mvnw.cmd: -------------------------------------------------------------------------------- 1 | <# : batch portion 2 | @REM ---------------------------------------------------------------------------- 3 | @REM Licensed to the Apache Software Foundation (ASF) under one 4 | @REM or more contributor license agreements. See the NOTICE file 5 | @REM distributed with this work for additional information 6 | @REM regarding copyright ownership. The ASF licenses this file 7 | @REM to you under the Apache License, Version 2.0 (the 8 | @REM "License"); you may not use this file except in compliance 9 | @REM with the License. You may obtain a copy of the License at 10 | @REM 11 | @REM https://www.apache.org/licenses/LICENSE-2.0 12 | @REM 13 | @REM Unless required by applicable law or agreed to in writing, 14 | @REM software distributed under the License is distributed on an 15 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | @REM KIND, either express or implied. See the License for the 17 | @REM specific language governing permissions and limitations 18 | @REM under the License. 19 | @REM ---------------------------------------------------------------------------- 20 | 21 | @REM ---------------------------------------------------------------------------- 22 | @REM Apache Maven Wrapper startup batch script, version 3.3.1 23 | @REM 24 | @REM Optional ENV vars 25 | @REM MVNW_REPOURL - repo url base for downloading maven distribution 26 | @REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven 27 | @REM MVNW_VERBOSE - true: enable verbose log; others: silence the output 28 | @REM ---------------------------------------------------------------------------- 29 | 30 | @IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) 31 | @SET __MVNW_CMD__= 32 | @SET __MVNW_ERROR__= 33 | @SET __MVNW_PSMODULEP_SAVE=%PSModulePath% 34 | @SET PSModulePath= 35 | @FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( 36 | IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) 37 | ) 38 | @SET PSModulePath=%__MVNW_PSMODULEP_SAVE% 39 | @SET __MVNW_PSMODULEP_SAVE= 40 | @SET __MVNW_ARG0_NAME__= 41 | @SET MVNW_USERNAME= 42 | @SET MVNW_PASSWORD= 43 | @IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) 44 | @echo Cannot start maven from wrapper >&2 && exit /b 1 45 | @GOTO :EOF 46 | : end batch / begin powershell #> 47 | 48 | $ErrorActionPreference = "Stop" 49 | if ($env:MVNW_VERBOSE -eq "true") { 50 | $VerbosePreference = "Continue" 51 | } 52 | 53 | # calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties 54 | $distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl 55 | if (!$distributionUrl) { 56 | Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" 57 | } 58 | 59 | switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { 60 | "maven-mvnd-*" { 61 | $USE_MVND = $true 62 | $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" 63 | $MVN_CMD = "mvnd.cmd" 64 | break 65 | } 66 | default { 67 | $USE_MVND = $false 68 | $MVN_CMD = $script -replace '^mvnw','mvn' 69 | break 70 | } 71 | } 72 | 73 | # apply MVNW_REPOURL and calculate MAVEN_HOME 74 | # maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ 75 | if ($env:MVNW_REPOURL) { 76 | $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } 77 | $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" 78 | } 79 | $distributionUrlName = $distributionUrl -replace '^.*/','' 80 | $distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' 81 | $MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" 82 | $MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' 83 | $MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" 84 | 85 | if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { 86 | Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" 87 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" 88 | exit $? 89 | } 90 | 91 | if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { 92 | Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" 93 | } 94 | 95 | # prepare tmp dir 96 | $TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile 97 | $TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" 98 | $TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null 99 | trap { 100 | if ($TMP_DOWNLOAD_DIR.Exists) { 101 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } 102 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } 103 | } 104 | } 105 | 106 | New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null 107 | 108 | # Download and Install Apache Maven 109 | Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." 110 | Write-Verbose "Downloading from: $distributionUrl" 111 | Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" 112 | 113 | $webclient = New-Object System.Net.WebClient 114 | if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { 115 | $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) 116 | } 117 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 118 | $webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null 119 | 120 | # If specified, validate the SHA-256 sum of the Maven distribution zip file 121 | $distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum 122 | if ($distributionSha256Sum) { 123 | if ($USE_MVND) { 124 | Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." 125 | } 126 | Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash 127 | if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { 128 | Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." 129 | } 130 | } 131 | 132 | # unzip and move 133 | Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null 134 | Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null 135 | try { 136 | Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null 137 | } catch { 138 | if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { 139 | Write-Error "fail to move MAVEN_HOME" 140 | } 141 | } finally { 142 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } 143 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } 144 | } 145 | 146 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" 147 | -------------------------------------------------------------------------------- /chatdv-backend/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.4.2 9 | 10 | 11 | com.example 12 | chatdv-backend 13 | 0.0.1-SNAPSHOT 14 | chatdv-backend 15 | ChatDV Backend 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 23 31 | 1.0.0-M6 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-web 37 | 38 | 39 | org.springframework.ai 40 | spring-ai-openai-spring-boot-starter 41 | 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-starter-test 46 | test 47 | 48 | 49 | 50 | 51 | 52 | org.springframework.ai 53 | spring-ai-bom 54 | ${spring-ai.version} 55 | pom 56 | import 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | org.springframework.boot 65 | spring-boot-maven-plugin 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /chatdv-backend/src/main/java/dev/danvega/Application.java: -------------------------------------------------------------------------------- 1 | package dev.danvega; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /chatdv-backend/src/main/java/dev/danvega/ChatController.java: -------------------------------------------------------------------------------- 1 | package dev.danvega; 2 | 3 | import org.springframework.ai.chat.client.ChatClient; 4 | import org.springframework.web.bind.annotation.CrossOrigin; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RequestParam; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | @RestController 10 | @CrossOrigin 11 | public class ChatController { 12 | 13 | private final ChatClient chatClient; 14 | 15 | public ChatController(ChatClient.Builder builder) { 16 | this.chatClient = builder.build(); 17 | } 18 | 19 | @GetMapping("/api/generate") 20 | public String generate(@RequestParam(value = "message") String message) { 21 | return chatClient.prompt() 22 | .user(message) 23 | .call() 24 | .content(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /chatdv-backend/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=chatdv-backend 2 | spring.ai.openai.api-key=${OPENAI_API_KEY} 3 | spring.ai.openai.chat.options.model=gpt-4o -------------------------------------------------------------------------------- /chatdv-backend/src/test/java/dev/danvega/ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package dev.danvega; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /chatdv-frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /chatdv-frontend/README.md: -------------------------------------------------------------------------------- 1 | # Vite + Vanilla JavaScript Example 2 | 3 | In this demo you will learn how to create a new project using Vite. We are going to create a frontend for our Spring Boot / Spring AI backend called `chatdv-backend` We will create a modern frontend using plain Vanilla JavaScript. 4 | 5 | ## Getting Started 6 | 7 | Before creating the frontend for this project make sure the [backend](https://github.com/spring-developer-frontend-landscape/chatdv-backend) project is running on port 8080. To create a new project 8 | using vite you can run the following command: 9 | 10 | ```shell 11 | npm create vite@latest 12 | ``` 13 | 14 | - name: chatdv-frontend 15 | - type: Vanilla JS 16 | - language: JavaScript 17 | -------------------------------------------------------------------------------- /chatdv-frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ChatDV ~ Vite, Vanilla JavaScript Demo 9 | 10 | 11 |
12 | 13 |
14 |
15 |
Yesterday
16 |
Tell me a Dad Joke about Dogs
17 |
Tell me a dad joke about Cats
18 |
What's the difference between Spring Framework and Spring Boot
19 |
Tell me a dad joke about Banks
20 |
Previous 7 Days
21 |
How can I write a shell script to open a new browser window
22 |
Previous 30 Days
23 |
What is the largest city in Ohio
24 |
What are some good places to visit while I'm in Barcelona
25 |
26 |
27 | 28 |
29 |
30 |
31 |
32 | 33 | 38 |
39 |
40 |
41 |
42 |

43 |

44 |
45 |
46 |
47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /chatdv-frontend/main.js: -------------------------------------------------------------------------------- 1 | const chatForm = document.getElementById('chatForm'); 2 | 3 | chatForm.addEventListener('submit', function(event) { 4 | event.preventDefault(); 5 | const messageInput = document.getElementById('message'); 6 | const message = messageInput.value; 7 | 8 | const response = document.getElementById('response'); 9 | fetch(`http://localhost:8080/api/generate?message=${message}`) 10 | .then((response) => response.text()) 11 | .then((data) => { 12 | response.innerHTML = '
' + data + '
'; 13 | }); 14 | }); -------------------------------------------------------------------------------- /chatdv-frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chatdv-frontend", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "typescript": "^5.2.2", 13 | "vite": "^5.2.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /chatdv-frontend/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /chatdv-htmx/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /chatdv-htmx/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | wrapperVersion=3.3.1 18 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip 19 | -------------------------------------------------------------------------------- /chatdv-htmx/README.md: -------------------------------------------------------------------------------- 1 | # ChatDV HTMX 2 | 3 | This is a demo of a Spring Boot application using htmx to add dynamic features without having to write JavaScript. The `ChatController`has 2 methods and the first one can be called without any other dependencies 4 | 5 | ```java 6 | @PostMapping("/old-generate") 7 | public String oldGenerate(@RequestParam String message, Model model) { 8 | String response = chatClient.call(message); 9 | model.addAttribute("response",response); 10 | 11 | // template :: fragmentName 12 | return "response :: responseFragment"; 13 | } 14 | ``` 15 | 16 | ```java 17 | @HxRequest 18 | @PostMapping("/generate") 19 | public HtmxResponse generate(@RequestParam String message, Model model) { 20 | log.info("User Message: {}", message); 21 | String response = chatClient.call(message); 22 | model.addAttribute("response",response); 23 | model.addAttribute("message",message); 24 | 25 | return HtmxResponse.builder() 26 | .view("response :: responseFragment") 27 | .view("todays-message-list :: messageFragment") 28 | .build(); 29 | } 30 | ``` -------------------------------------------------------------------------------- /chatdv-htmx/mvnw.cmd: -------------------------------------------------------------------------------- 1 | <# : batch portion 2 | @REM ---------------------------------------------------------------------------- 3 | @REM Licensed to the Apache Software Foundation (ASF) under one 4 | @REM or more contributor license agreements. See the NOTICE file 5 | @REM distributed with this work for additional information 6 | @REM regarding copyright ownership. The ASF licenses this file 7 | @REM to you under the Apache License, Version 2.0 (the 8 | @REM "License"); you may not use this file except in compliance 9 | @REM with the License. You may obtain a copy of the License at 10 | @REM 11 | @REM https://www.apache.org/licenses/LICENSE-2.0 12 | @REM 13 | @REM Unless required by applicable law or agreed to in writing, 14 | @REM software distributed under the License is distributed on an 15 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | @REM KIND, either express or implied. See the License for the 17 | @REM specific language governing permissions and limitations 18 | @REM under the License. 19 | @REM ---------------------------------------------------------------------------- 20 | 21 | @REM ---------------------------------------------------------------------------- 22 | @REM Apache Maven Wrapper startup batch script, version 3.3.1 23 | @REM 24 | @REM Optional ENV vars 25 | @REM MVNW_REPOURL - repo url base for downloading maven distribution 26 | @REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven 27 | @REM MVNW_VERBOSE - true: enable verbose log; others: silence the output 28 | @REM ---------------------------------------------------------------------------- 29 | 30 | @IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) 31 | @SET __MVNW_CMD__= 32 | @SET __MVNW_ERROR__= 33 | @SET __MVNW_PSMODULEP_SAVE=%PSModulePath% 34 | @SET PSModulePath= 35 | @FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( 36 | IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) 37 | ) 38 | @SET PSModulePath=%__MVNW_PSMODULEP_SAVE% 39 | @SET __MVNW_PSMODULEP_SAVE= 40 | @SET __MVNW_ARG0_NAME__= 41 | @SET MVNW_USERNAME= 42 | @SET MVNW_PASSWORD= 43 | @IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) 44 | @echo Cannot start maven from wrapper >&2 && exit /b 1 45 | @GOTO :EOF 46 | : end batch / begin powershell #> 47 | 48 | $ErrorActionPreference = "Stop" 49 | if ($env:MVNW_VERBOSE -eq "true") { 50 | $VerbosePreference = "Continue" 51 | } 52 | 53 | # calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties 54 | $distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl 55 | if (!$distributionUrl) { 56 | Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" 57 | } 58 | 59 | switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { 60 | "maven-mvnd-*" { 61 | $USE_MVND = $true 62 | $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" 63 | $MVN_CMD = "mvnd.cmd" 64 | break 65 | } 66 | default { 67 | $USE_MVND = $false 68 | $MVN_CMD = $script -replace '^mvnw','mvn' 69 | break 70 | } 71 | } 72 | 73 | # apply MVNW_REPOURL and calculate MAVEN_HOME 74 | # maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ 75 | if ($env:MVNW_REPOURL) { 76 | $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } 77 | $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" 78 | } 79 | $distributionUrlName = $distributionUrl -replace '^.*/','' 80 | $distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' 81 | $MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" 82 | $MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' 83 | $MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" 84 | 85 | if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { 86 | Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" 87 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" 88 | exit $? 89 | } 90 | 91 | if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { 92 | Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" 93 | } 94 | 95 | # prepare tmp dir 96 | $TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile 97 | $TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" 98 | $TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null 99 | trap { 100 | if ($TMP_DOWNLOAD_DIR.Exists) { 101 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } 102 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } 103 | } 104 | } 105 | 106 | New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null 107 | 108 | # Download and Install Apache Maven 109 | Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." 110 | Write-Verbose "Downloading from: $distributionUrl" 111 | Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" 112 | 113 | $webclient = New-Object System.Net.WebClient 114 | if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { 115 | $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) 116 | } 117 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 118 | $webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null 119 | 120 | # If specified, validate the SHA-256 sum of the Maven distribution zip file 121 | $distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum 122 | if ($distributionSha256Sum) { 123 | if ($USE_MVND) { 124 | Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." 125 | } 126 | Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash 127 | if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { 128 | Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." 129 | } 130 | } 131 | 132 | # unzip and move 133 | Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null 134 | Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null 135 | try { 136 | Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null 137 | } catch { 138 | if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { 139 | Write-Error "fail to move MAVEN_HOME" 140 | } 141 | } finally { 142 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } 143 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } 144 | } 145 | 146 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" 147 | -------------------------------------------------------------------------------- /chatdv-htmx/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.4.3 9 | 10 | 11 | dev.danvega 12 | chatdv-htmx 13 | 0.0.1-SNAPSHOT 14 | chatdv-htmx 15 | HTMX Demo 16 | 17 | 23 18 | 1.0.0-M6 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-thymeleaf 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-web 28 | 29 | 30 | org.springframework.ai 31 | spring-ai-openai-spring-boot-starter 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-devtools 36 | runtime 37 | true 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-test 42 | test 43 | 44 | 45 | 46 | 47 | 48 | org.springframework.ai 49 | spring-ai-bom 50 | ${spring-ai.version} 51 | pom 52 | import 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | org.springframework.boot 61 | spring-boot-maven-plugin 62 | 63 | 64 | 65 | 66 | 67 | spring-milestones 68 | Spring Milestones 69 | https://repo.spring.io/milestone 70 | 71 | false 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /chatdv-htmx/src/main/java/dev/danvega/chatdv_htmx/Application.java: -------------------------------------------------------------------------------- 1 | package dev.danvega.chatdv_htmx; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /chatdv-htmx/src/main/java/dev/danvega/chatdv_htmx/ChatController.java: -------------------------------------------------------------------------------- 1 | package dev.danvega.chatdv_htmx; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.ai.chat.client.ChatClient; 6 | import org.springframework.stereotype.Controller; 7 | import org.springframework.ui.Model; 8 | import org.springframework.web.bind.annotation.*; 9 | import org.springframework.web.servlet.ModelAndView; 10 | 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | @Controller 15 | public class ChatController { 16 | 17 | private static final Logger log = LoggerFactory.getLogger(ChatController.class); 18 | private final ChatClient chatClient; 19 | 20 | public ChatController(ChatClient.Builder builder) { 21 | this.chatClient = builder.build(); 22 | } 23 | 24 | @GetMapping("") 25 | public String home() { 26 | return "index"; 27 | } 28 | 29 | @PostMapping("/generate") 30 | public List generate(@RequestParam String message) { 31 | log.info("User Message: {}", message); 32 | String response = chatClient.prompt() 33 | .user(message) 34 | .call() 35 | .content(); 36 | 37 | return List.of( 38 | new ModelAndView("response :: responseFragment", 39 | Map.of("response", response)), 40 | new ModelAndView("todays-message-list :: messageFragment", 41 | Map.of("message", message)), 42 | new ModelAndView("chat-form :: formFragment") 43 | ); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /chatdv-htmx/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=chatdv-htmx 2 | spring.ai.openai.api-key=${OPENAI_API_KEY} 3 | spring.ai.openai.chat.options.model=gpt-4o -------------------------------------------------------------------------------- /chatdv-htmx/src/main/resources/templates/chat-form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 |
11 |
14 |
15 | 16 | 21 |
22 |
23 |
24 | 25 | -------------------------------------------------------------------------------- /chatdv-htmx/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | ChatDV - HTMX 9 | 10 | 11 | 12 | 13 |
14 | 15 |
16 |
17 |
Today
18 |
Yesterday
19 |
Tell me a Dad Joke about Dogs
20 |
Tell me a dad joke about Cats
21 |
22 |
23 | 24 |
25 | 26 |
27 |
28 |
29 |
30 |
31 | 32 | 33 |
34 |
35 |
36 |
37 |
38 | -------------------------------------------------------------------------------- /chatdv-htmx/src/main/resources/templates/response.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 |
11 |

12 |
13 | -------------------------------------------------------------------------------- /chatdv-htmx/src/main/resources/templates/todays-message-list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 |
11 |
MESSAGE
12 |
13 | -------------------------------------------------------------------------------- /chatdv-htmx/src/test/java/dev/danvega/chatdv_htmx/ChatdvHtmxApplicationTests.java: -------------------------------------------------------------------------------- 1 | package dev.danvega.chatdv_htmx; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ChatdvHtmxApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /full-stack-spring-vue/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | .DS_Store 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | 17 | ### IntelliJ IDEA ### 18 | .idea 19 | *.iws 20 | *.iml 21 | *.ipr 22 | 23 | ### NetBeans ### 24 | /nbproject/private/ 25 | /nbbuild/ 26 | /dist/ 27 | /nbdist/ 28 | /.nb-gradle/ 29 | build/ 30 | !**/src/main/**/build/ 31 | !**/src/test/**/build/ 32 | 33 | ### VS Code ### 34 | .vscode/ 35 | 36 | ### frontend 37 | /src/frontend/node/ 38 | /src/frontend/node_modules 39 | /src/frontend/dist -------------------------------------------------------------------------------- /full-stack-spring-vue/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | wrapperVersion=3.3.1 18 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip 19 | -------------------------------------------------------------------------------- /full-stack-spring-vue/README.md: -------------------------------------------------------------------------------- 1 | # Full-Stack Java / Spring & Vue Example 2 | 3 | This is a template for anyone looking to use Spring Boot + Vue.JS in the same project. 4 | 5 | ## Development 6 | 7 | - Run the Spring Boot application which will run on port 8080 8 | - Run the Vue application (/src/frontend) which will run on port 3000 9 | - All calls to `/api/**` are proxied to 8080 thanks to `vite.config.js` 10 | 11 | If you want to start both the Spring Boot Application and Vue app you can run the `run.sh` script. 12 | 13 | ## Packaging 14 | 15 | When you run `mvn clean package` the frontend Vue application will build in the `dist` directory. 16 | The Maven plugin `maven-resources-plugin` will copy the contents of the build directory into `/target/static/classes` 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /full-stack-spring-vue/mvnw.cmd: -------------------------------------------------------------------------------- 1 | <# : batch portion 2 | @REM ---------------------------------------------------------------------------- 3 | @REM Licensed to the Apache Software Foundation (ASF) under one 4 | @REM or more contributor license agreements. See the NOTICE file 5 | @REM distributed with this work for additional information 6 | @REM regarding copyright ownership. The ASF licenses this file 7 | @REM to you under the Apache License, Version 2.0 (the 8 | @REM "License"); you may not use this file except in compliance 9 | @REM with the License. You may obtain a copy of the License at 10 | @REM 11 | @REM https://www.apache.org/licenses/LICENSE-2.0 12 | @REM 13 | @REM Unless required by applicable law or agreed to in writing, 14 | @REM software distributed under the License is distributed on an 15 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | @REM KIND, either express or implied. See the License for the 17 | @REM specific language governing permissions and limitations 18 | @REM under the License. 19 | @REM ---------------------------------------------------------------------------- 20 | 21 | @REM ---------------------------------------------------------------------------- 22 | @REM Apache Maven Wrapper startup batch script, version 3.3.1 23 | @REM 24 | @REM Optional ENV vars 25 | @REM MVNW_REPOURL - repo url base for downloading maven distribution 26 | @REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven 27 | @REM MVNW_VERBOSE - true: enable verbose log; others: silence the output 28 | @REM ---------------------------------------------------------------------------- 29 | 30 | @IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) 31 | @SET __MVNW_CMD__= 32 | @SET __MVNW_ERROR__= 33 | @SET __MVNW_PSMODULEP_SAVE=%PSModulePath% 34 | @SET PSModulePath= 35 | @FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( 36 | IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) 37 | ) 38 | @SET PSModulePath=%__MVNW_PSMODULEP_SAVE% 39 | @SET __MVNW_PSMODULEP_SAVE= 40 | @SET __MVNW_ARG0_NAME__= 41 | @SET MVNW_USERNAME= 42 | @SET MVNW_PASSWORD= 43 | @IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) 44 | @echo Cannot start maven from wrapper >&2 && exit /b 1 45 | @GOTO :EOF 46 | : end batch / begin powershell #> 47 | 48 | $ErrorActionPreference = "Stop" 49 | if ($env:MVNW_VERBOSE -eq "true") { 50 | $VerbosePreference = "Continue" 51 | } 52 | 53 | # calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties 54 | $distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl 55 | if (!$distributionUrl) { 56 | Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" 57 | } 58 | 59 | switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { 60 | "maven-mvnd-*" { 61 | $USE_MVND = $true 62 | $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" 63 | $MVN_CMD = "mvnd.cmd" 64 | break 65 | } 66 | default { 67 | $USE_MVND = $false 68 | $MVN_CMD = $script -replace '^mvnw','mvn' 69 | break 70 | } 71 | } 72 | 73 | # apply MVNW_REPOURL and calculate MAVEN_HOME 74 | # maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ 75 | if ($env:MVNW_REPOURL) { 76 | $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } 77 | $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" 78 | } 79 | $distributionUrlName = $distributionUrl -replace '^.*/','' 80 | $distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' 81 | $MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" 82 | $MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' 83 | $MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" 84 | 85 | if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { 86 | Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" 87 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" 88 | exit $? 89 | } 90 | 91 | if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { 92 | Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" 93 | } 94 | 95 | # prepare tmp dir 96 | $TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile 97 | $TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" 98 | $TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null 99 | trap { 100 | if ($TMP_DOWNLOAD_DIR.Exists) { 101 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } 102 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } 103 | } 104 | } 105 | 106 | New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null 107 | 108 | # Download and Install Apache Maven 109 | Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." 110 | Write-Verbose "Downloading from: $distributionUrl" 111 | Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" 112 | 113 | $webclient = New-Object System.Net.WebClient 114 | if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { 115 | $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) 116 | } 117 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 118 | $webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null 119 | 120 | # If specified, validate the SHA-256 sum of the Maven distribution zip file 121 | $distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum 122 | if ($distributionSha256Sum) { 123 | if ($USE_MVND) { 124 | Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." 125 | } 126 | Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash 127 | if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { 128 | Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." 129 | } 130 | } 131 | 132 | # unzip and move 133 | Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null 134 | Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null 135 | try { 136 | Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null 137 | } catch { 138 | if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { 139 | Write-Error "fail to move MAVEN_HOME" 140 | } 141 | } finally { 142 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } 143 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } 144 | } 145 | 146 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" 147 | -------------------------------------------------------------------------------- /full-stack-spring-vue/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.4.3 9 | 10 | 11 | dev.danvega 12 | full-stuck-spring-vue 13 | 0.0.1-SNAPSHOT 14 | full-stuck-spring-vue 15 | Demo project for Spring Boot 16 | 17 | 21 18 | v20.2.0 19 | 9.8.1 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-actuator 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-web 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-devtools 34 | runtime 35 | true 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-starter-test 40 | test 41 | 42 | 43 | 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-maven-plugin 49 | 50 | 51 | 52 | com.github.eirslett 53 | frontend-maven-plugin 54 | 1.12.1 55 | 56 | 57 | 58 | Install node and npm 59 | 60 | install-node-and-npm 61 | 62 | generate-resources 63 | 64 | ${node.version} 65 | ${npm.version} 66 | 67 | 68 | 69 | 70 | npm install 71 | 72 | npm 73 | 74 | generate-resources 75 | 76 | install 77 | 78 | 79 | 80 | 81 | npm build 82 | 83 | npm 84 | 85 | generate-resources 86 | 87 | run build 88 | 89 | 90 | 91 | 92 | ${node.version} 93 | src/frontend 94 | 95 | 96 | 97 | 98 | 99 | org.apache.maven.plugins 100 | maven-resources-plugin 101 | 102 | 103 | Copy Vue frontend into Spring Boot target static folder 104 | process-resources 105 | 106 | copy-resources 107 | 108 | 109 | target/classes/static 110 | 111 | 112 | src/frontend/dist 113 | true 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /full-stack-spring-vue/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | # Run the Spring Boot application 4 | mvn spring-boot:run & 5 | 6 | # Wait for the Spring Boot application to start 7 | sleep 5 8 | 9 | # Run the frontend application 10 | npm run dev --prefix src/frontend & 11 | 12 | # Wait for the frontend application to start 13 | sleep 2 14 | 15 | # Open the URL in the default web browser 16 | open http://localhost:5173 -------------------------------------------------------------------------------- /full-stack-spring-vue/src/frontend/.env: -------------------------------------------------------------------------------- 1 | VITE_API_URL=http://localhost:8080 -------------------------------------------------------------------------------- /full-stack-spring-vue/src/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /full-stack-spring-vue/src/frontend/README.md: -------------------------------------------------------------------------------- 1 | # Vue 3 + Vite 2 | 3 | This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 ` 12 | 13 | 14 | -------------------------------------------------------------------------------- /full-stack-spring-vue/src/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "vue": "^3.4.21" 13 | }, 14 | "devDependencies": { 15 | "@vitejs/plugin-vue": "^5.0.4", 16 | "vite": "^5.2.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /full-stack-spring-vue/src/frontend/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /full-stack-spring-vue/src/frontend/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 23 | -------------------------------------------------------------------------------- /full-stack-spring-vue/src/frontend/src/assets/vue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /full-stack-spring-vue/src/frontend/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /full-stack-spring-vue/src/frontend/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import './style.css' 3 | import App from './App.vue' 4 | 5 | createApp(App).mount('#app') 6 | -------------------------------------------------------------------------------- /full-stack-spring-vue/src/frontend/src/style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | a:hover { 22 | color: #535bf2; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | display: flex; 28 | place-items: center; 29 | min-width: 320px; 30 | min-height: 100vh; 31 | } 32 | 33 | h1 { 34 | font-size: 3.2em; 35 | line-height: 1.1; 36 | } 37 | 38 | button { 39 | border-radius: 8px; 40 | border: 1px solid transparent; 41 | padding: 0.6em 1.2em; 42 | font-size: 1em; 43 | font-weight: 500; 44 | font-family: inherit; 45 | background-color: #1a1a1a; 46 | cursor: pointer; 47 | transition: border-color 0.25s; 48 | } 49 | button:hover { 50 | border-color: #646cff; 51 | } 52 | button:focus, 53 | button:focus-visible { 54 | outline: 4px auto -webkit-focus-ring-color; 55 | } 56 | 57 | .card { 58 | padding: 2em; 59 | } 60 | 61 | #app { 62 | max-width: 1280px; 63 | margin: 0 auto; 64 | padding: 2rem; 65 | text-align: center; 66 | } 67 | 68 | @media (prefers-color-scheme: light) { 69 | :root { 70 | color: #213547; 71 | background-color: #ffffff; 72 | } 73 | a:hover { 74 | color: #747bff; 75 | } 76 | button { 77 | background-color: #f9f9f9; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /full-stack-spring-vue/src/frontend/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig, loadEnv } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig(({mode}) => { 6 | const env = loadEnv(mode, process.cwd()); 7 | const API_URL = `${env.VITE_API_URL ?? 'http://localhost:8080'}`; 8 | return { 9 | server: { 10 | proxy: { 11 | '/api': { 12 | target: API_URL, 13 | changeOrigin: true 14 | } 15 | } 16 | }, 17 | plugins: [vue()] 18 | }; 19 | }) 20 | 21 | -------------------------------------------------------------------------------- /full-stack-spring-vue/src/main/java/dev/danvega/Application.java: -------------------------------------------------------------------------------- 1 | package dev.danvega; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /full-stack-spring-vue/src/main/java/dev/danvega/MessageController.java: -------------------------------------------------------------------------------- 1 | package dev.danvega; 2 | 3 | import org.springframework.web.bind.annotation.CrossOrigin; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | @RestController 9 | @RequestMapping("/api/messages") 10 | @CrossOrigin 11 | public class MessageController { 12 | 13 | @GetMapping("") 14 | public String home() { 15 | return "Hello, Spring & Vue 👋🏻"; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /full-stack-spring-vue/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=full-stuck-spring-vue 2 | -------------------------------------------------------------------------------- /full-stack-spring-vue/src/test/java/dev/danvega/FullStuckSpringVueApplicationTests.java: -------------------------------------------------------------------------------- 1 | package dev.danvega; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class FullStuckSpringVueApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /spring-mvc-sessions/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /spring-mvc-sessions/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | wrapperVersion=3.3.1 18 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip 19 | -------------------------------------------------------------------------------- /spring-mvc-sessions/README.md: -------------------------------------------------------------------------------- 1 | # Spring I/O Sessions 2 | 3 | This is a simple Spring MVC application that will display a list of sessions from the conference. 4 | This is both a traditional MVC app with views using Thymeleaf, and it also exposes a REST API for a vue frontend. 5 | -------------------------------------------------------------------------------- /spring-mvc-sessions/mvnw.cmd: -------------------------------------------------------------------------------- 1 | <# : batch portion 2 | @REM ---------------------------------------------------------------------------- 3 | @REM Licensed to the Apache Software Foundation (ASF) under one 4 | @REM or more contributor license agreements. See the NOTICE file 5 | @REM distributed with this work for additional information 6 | @REM regarding copyright ownership. The ASF licenses this file 7 | @REM to you under the Apache License, Version 2.0 (the 8 | @REM "License"); you may not use this file except in compliance 9 | @REM with the License. You may obtain a copy of the License at 10 | @REM 11 | @REM https://www.apache.org/licenses/LICENSE-2.0 12 | @REM 13 | @REM Unless required by applicable law or agreed to in writing, 14 | @REM software distributed under the License is distributed on an 15 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | @REM KIND, either express or implied. See the License for the 17 | @REM specific language governing permissions and limitations 18 | @REM under the License. 19 | @REM ---------------------------------------------------------------------------- 20 | 21 | @REM ---------------------------------------------------------------------------- 22 | @REM Apache Maven Wrapper startup batch script, version 3.3.1 23 | @REM 24 | @REM Optional ENV vars 25 | @REM MVNW_REPOURL - repo url base for downloading maven distribution 26 | @REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven 27 | @REM MVNW_VERBOSE - true: enable verbose log; others: silence the output 28 | @REM ---------------------------------------------------------------------------- 29 | 30 | @IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) 31 | @SET __MVNW_CMD__= 32 | @SET __MVNW_ERROR__= 33 | @SET __MVNW_PSMODULEP_SAVE=%PSModulePath% 34 | @SET PSModulePath= 35 | @FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( 36 | IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) 37 | ) 38 | @SET PSModulePath=%__MVNW_PSMODULEP_SAVE% 39 | @SET __MVNW_PSMODULEP_SAVE= 40 | @SET __MVNW_ARG0_NAME__= 41 | @SET MVNW_USERNAME= 42 | @SET MVNW_PASSWORD= 43 | @IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) 44 | @echo Cannot start maven from wrapper >&2 && exit /b 1 45 | @GOTO :EOF 46 | : end batch / begin powershell #> 47 | 48 | $ErrorActionPreference = "Stop" 49 | if ($env:MVNW_VERBOSE -eq "true") { 50 | $VerbosePreference = "Continue" 51 | } 52 | 53 | # calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties 54 | $distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl 55 | if (!$distributionUrl) { 56 | Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" 57 | } 58 | 59 | switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { 60 | "maven-mvnd-*" { 61 | $USE_MVND = $true 62 | $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" 63 | $MVN_CMD = "mvnd.cmd" 64 | break 65 | } 66 | default { 67 | $USE_MVND = $false 68 | $MVN_CMD = $script -replace '^mvnw','mvn' 69 | break 70 | } 71 | } 72 | 73 | # apply MVNW_REPOURL and calculate MAVEN_HOME 74 | # maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ 75 | if ($env:MVNW_REPOURL) { 76 | $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } 77 | $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" 78 | } 79 | $distributionUrlName = $distributionUrl -replace '^.*/','' 80 | $distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' 81 | $MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" 82 | $MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' 83 | $MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" 84 | 85 | if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { 86 | Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" 87 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" 88 | exit $? 89 | } 90 | 91 | if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { 92 | Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" 93 | } 94 | 95 | # prepare tmp dir 96 | $TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile 97 | $TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" 98 | $TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null 99 | trap { 100 | if ($TMP_DOWNLOAD_DIR.Exists) { 101 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } 102 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } 103 | } 104 | } 105 | 106 | New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null 107 | 108 | # Download and Install Apache Maven 109 | Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." 110 | Write-Verbose "Downloading from: $distributionUrl" 111 | Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" 112 | 113 | $webclient = New-Object System.Net.WebClient 114 | if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { 115 | $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) 116 | } 117 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 118 | $webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null 119 | 120 | # If specified, validate the SHA-256 sum of the Maven distribution zip file 121 | $distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum 122 | if ($distributionSha256Sum) { 123 | if ($USE_MVND) { 124 | Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." 125 | } 126 | Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash 127 | if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { 128 | Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." 129 | } 130 | } 131 | 132 | # unzip and move 133 | Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null 134 | Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null 135 | try { 136 | Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null 137 | } catch { 138 | if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { 139 | Write-Error "fail to move MAVEN_HOME" 140 | } 141 | } finally { 142 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } 143 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } 144 | } 145 | 146 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" 147 | -------------------------------------------------------------------------------- /spring-mvc-sessions/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.4.3 9 | 10 | 11 | dev.danvega 12 | sessions 13 | 0.0.1-SNAPSHOT 14 | sessions 15 | Demo project for Spring Boot 16 | 17 | 23 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-web 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-devtools 27 | 28 | 29 | gg.jte 30 | jte 31 | 3.1.12 32 | 33 | 34 | gg.jte 35 | jte-spring-boot-starter-3 36 | 3.1.12 37 | 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-test 42 | test 43 | 44 | 45 | 46 | 47 | 48 | 49 | gg.jte 50 | jte-maven-plugin 51 | 3.1.12 52 | 53 | 54 | jte-generate 55 | generate-sources 56 | 57 | generate 58 | 59 | 60 | ${project.basedir}/src/main/jte 61 | Html 62 | true 63 | ${project.build.outputDirectory} 64 | 65 | 66 | 67 | 68 | 69 | org.springframework.boot 70 | spring-boot-maven-plugin 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /spring-mvc-sessions/src/main/java/dev/danvega/conference/Application.java: -------------------------------------------------------------------------------- 1 | package dev.danvega.conference; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /spring-mvc-sessions/src/main/java/dev/danvega/conference/session/Session.java: -------------------------------------------------------------------------------- 1 | package dev.danvega.conference.session; 2 | 3 | import java.util.List; 4 | import java.util.stream.Collectors; 5 | 6 | public record Session (String title, List speakers) { 7 | 8 | public String getSpeakersAsString() { 9 | return speakers.stream().collect(Collectors.joining(",")); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /spring-mvc-sessions/src/main/java/dev/danvega/conference/session/SessionApiController.java: -------------------------------------------------------------------------------- 1 | package dev.danvega.conference.session; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.web.bind.annotation.CrossOrigin; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | import java.util.List; 11 | 12 | @RestController 13 | @RequestMapping("/api/sessions") 14 | @CrossOrigin 15 | public class SessionApiController { 16 | 17 | private static final Logger log = LoggerFactory.getLogger(SessionApiController.class); 18 | private final SessionRepository repository; 19 | 20 | public SessionApiController(SessionRepository repository) { 21 | this.repository = repository; 22 | } 23 | 24 | @GetMapping("") 25 | public List findAll() { 26 | return repository.findAll(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /spring-mvc-sessions/src/main/java/dev/danvega/conference/session/SessionController.java: -------------------------------------------------------------------------------- 1 | package dev.danvega.conference.session; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.ui.Model; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | 7 | @Controller 8 | public class SessionController { 9 | 10 | private final SessionRepository repository; 11 | 12 | public SessionController(SessionRepository repository) { 13 | this.repository = repository; 14 | } 15 | 16 | @GetMapping("") 17 | public String index(Model model) { 18 | model.addAttribute("sessions",repository.findAll()); 19 | return "index"; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /spring-mvc-sessions/src/main/java/dev/danvega/conference/session/SessionRepository.java: -------------------------------------------------------------------------------- 1 | package dev.danvega.conference.session; 2 | 3 | import com.fasterxml.jackson.core.type.TypeReference; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import jakarta.annotation.PostConstruct; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.stereotype.Repository; 9 | 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | @Repository 16 | public class SessionRepository { 17 | 18 | private static final Logger log = LoggerFactory.getLogger(SessionRepository.class); 19 | private final List sessions = new ArrayList<>(); 20 | private final ObjectMapper objectMapper; 21 | 22 | public SessionRepository(ObjectMapper objectMapper) { 23 | this.objectMapper = objectMapper; 24 | } 25 | 26 | public List findAll() { 27 | return sessions; 28 | } 29 | 30 | @PostConstruct 31 | private void init() { 32 | 33 | if(sessions.isEmpty()) { 34 | try (InputStream inputStream = TypeReference.class.getResourceAsStream("/data/sessions.json")) { 35 | Sessions allSessions = objectMapper.readValue(inputStream, Sessions.class); 36 | log.info("Reading {} sessions from JSON data", allSessions.sessions().size()); 37 | sessions.addAll(allSessions.sessions()); 38 | } catch (IOException e) { 39 | throw new RuntimeException("Failed to read JSON data", e); 40 | } 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /spring-mvc-sessions/src/main/java/dev/danvega/conference/session/Sessions.java: -------------------------------------------------------------------------------- 1 | package dev.danvega.conference.session; 2 | 3 | import java.util.List; 4 | 5 | public record Sessions(List sessions) { 6 | } 7 | -------------------------------------------------------------------------------- /spring-mvc-sessions/src/main/jte/.jteroot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danvega/java-developer-frontend-landscape/bc4cbd276c7a4d53b5e3d6e47833b63b81b8cf73/spring-mvc-sessions/src/main/jte/.jteroot -------------------------------------------------------------------------------- /spring-mvc-sessions/src/main/jte/index.jte: -------------------------------------------------------------------------------- 1 | @param java.util.List sessions 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | Session List 12 | 13 | 14 | 15 |

16 | JavaOne 2025 Sessions 17 |

18 | 19 |
20 |
21 |
22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | @for(var s : sessions) 32 | 33 | 36 | 39 | 40 | @endfor 41 | 42 |
TitleName
34 | ${s.title()} 35 | 37 | ${s.getSpeakersAsString()} 38 |
43 |
44 |
45 |
46 |
47 | 48 | 49 | -------------------------------------------------------------------------------- /spring-mvc-sessions/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=sessions 2 | gg.jte.development-mode=true 3 | logging.level.org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver=OFF -------------------------------------------------------------------------------- /spring-mvc-sessions/src/test/java/dev/danvega/conference/SessionsApplicationTests.java: -------------------------------------------------------------------------------- 1 | package dev.danvega.conference; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class SessionsApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /vaadin-sessions/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /vaadin-sessions/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /vaadin-sessions/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /vaadin-sessions/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /vaadin-sessions/.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /vaadin-sessions/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /vaadin-sessions/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /vaadin-sessions/README.md: -------------------------------------------------------------------------------- 1 | # Vaadin Sessions 2 | 3 | This is a simple example that will display a list of sessions from DevNexus 2025. The sessions are loaded from the JSON 4 | file located in `/data/sessions.json`. The UI is built entirely in Java using Vaadin Flow. -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/flow/generated-flow-imports.d.ts: -------------------------------------------------------------------------------- 1 | export {} -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/flow/generated-flow-imports.js: -------------------------------------------------------------------------------- 1 | import '@vaadin/field-highlighter/src/vaadin-field-highlighter.js'; 2 | import '@vaadin/common-frontend/ConnectionIndicator.js'; 3 | import '@vaadin/polymer-legacy-adapter/style-modules.js'; 4 | import '@vaadin/accordion/src/vaadin-accordion.js'; 5 | import '@vaadin/details/src/vaadin-details.js'; 6 | import '@vaadin/accordion/src/vaadin-accordion-panel.js'; 7 | import '@vaadin/app-layout/src/vaadin-app-layout.js'; 8 | import '@vaadin/button/src/vaadin-button.js'; 9 | import '@vaadin/app-layout/src/vaadin-drawer-toggle.js'; 10 | import '@vaadin/avatar/src/vaadin-avatar.js'; 11 | import '@vaadin/avatar-group/src/vaadin-avatar-group.js'; 12 | import '@vaadin/checkbox/src/vaadin-checkbox.js'; 13 | import '@vaadin/checkbox-group/src/vaadin-checkbox-group.js'; 14 | import '@vaadin/combo-box/src/vaadin-combo-box.js'; 15 | import 'Frontend/generated/jar-resources/flow-component-renderer.js'; 16 | import 'Frontend/generated/jar-resources/comboBoxConnector.js'; 17 | import '@vaadin/multi-select-combo-box/src/vaadin-multi-select-combo-box.js'; 18 | import '@vaadin/confirm-dialog/src/vaadin-confirm-dialog.js'; 19 | import '@vaadin/context-menu/src/vaadin-context-menu.js'; 20 | import 'Frontend/generated/jar-resources/contextMenuConnector.js'; 21 | import 'Frontend/generated/jar-resources/contextMenuTargetConnector.js'; 22 | import '@vaadin/custom-field/src/vaadin-custom-field.js'; 23 | import '@vaadin/date-picker/src/vaadin-date-picker.js'; 24 | import 'Frontend/generated/jar-resources/datepickerConnector.js'; 25 | import '@vaadin/date-time-picker/src/vaadin-date-time-picker.js'; 26 | import '@vaadin/time-picker/src/vaadin-time-picker.js'; 27 | import 'Frontend/generated/jar-resources/vaadin-time-picker/timepickerConnector.js'; 28 | import '@vaadin/dialog/src/vaadin-dialog.js'; 29 | import 'Frontend/generated/jar-resources/dndConnector.js'; 30 | import '@vaadin/form-layout/src/vaadin-form-layout.js'; 31 | import '@vaadin/form-layout/src/vaadin-form-item.js'; 32 | import '@vaadin/grid/src/vaadin-grid-column-group.js'; 33 | import '@vaadin/grid/src/vaadin-grid.js'; 34 | import '@vaadin/grid/src/vaadin-grid-column.js'; 35 | import '@vaadin/grid/src/vaadin-grid-sorter.js'; 36 | import 'Frontend/generated/jar-resources/gridConnector.ts'; 37 | import '@vaadin/tooltip/src/vaadin-tooltip.js'; 38 | import 'Frontend/generated/jar-resources/vaadin-grid-flow-selection-column.js'; 39 | import '@vaadin/icon/src/vaadin-icon.js'; 40 | import '@vaadin/icons/vaadin-iconset.js'; 41 | import '@vaadin/list-box/src/vaadin-list-box.js'; 42 | import '@vaadin/item/src/vaadin-item.js'; 43 | import '@vaadin/login/src/vaadin-login-form.js'; 44 | import '@vaadin/login/src/vaadin-login-overlay.js'; 45 | import 'Frontend/generated/jar-resources/menubarConnector.js'; 46 | import '@vaadin/menu-bar/src/vaadin-menu-bar.js'; 47 | import '@vaadin/message-input/src/vaadin-message-input.js'; 48 | import 'Frontend/generated/jar-resources/messageListConnector.js'; 49 | import '@vaadin/message-list/src/vaadin-message-list.js'; 50 | import '@vaadin/notification/src/vaadin-notification.js'; 51 | import '@vaadin/horizontal-layout/src/vaadin-horizontal-layout.js'; 52 | import '@vaadin/scroller/src/vaadin-scroller.js'; 53 | import '@vaadin/vertical-layout/src/vaadin-vertical-layout.js'; 54 | import '@vaadin/popover/src/vaadin-popover.js'; 55 | import 'Frontend/generated/jar-resources/vaadin-popover/popover.ts'; 56 | import '@vaadin/progress-bar/src/vaadin-progress-bar.js'; 57 | import '@vaadin/radio-group/src/vaadin-radio-button.js'; 58 | import '@vaadin/radio-group/src/vaadin-radio-group.js'; 59 | import 'Frontend/generated/jar-resources/ReactRouterOutletElement.tsx'; 60 | import '@vaadin/select/src/vaadin-select.js'; 61 | import 'Frontend/generated/jar-resources/selectConnector.js'; 62 | import 'Frontend/generated/jar-resources/tooltip.ts'; 63 | import 'Frontend/generated/jar-resources/disableOnClickFunctions.js'; 64 | import '@vaadin/side-nav/src/vaadin-side-nav.js'; 65 | import '@vaadin/side-nav/src/vaadin-side-nav-item.js'; 66 | import '@vaadin/split-layout/src/vaadin-split-layout.js'; 67 | import '@vaadin/tabs/src/vaadin-tab.js'; 68 | import '@vaadin/tabsheet/src/vaadin-tabsheet.js'; 69 | import '@vaadin/tabs/src/vaadin-tabs.js'; 70 | import 'Frontend/generated/jar-resources/vaadin-big-decimal-field.js'; 71 | import '@vaadin/email-field/src/vaadin-email-field.js'; 72 | import '@vaadin/integer-field/src/vaadin-integer-field.js'; 73 | import '@vaadin/number-field/src/vaadin-number-field.js'; 74 | import '@vaadin/password-field/src/vaadin-password-field.js'; 75 | import '@vaadin/text-area/src/vaadin-text-area.js'; 76 | import '@vaadin/text-field/src/vaadin-text-field.js'; 77 | import 'Frontend/generated/jar-resources/lit-renderer.ts'; 78 | import '@vaadin/grid/src/vaadin-grid-tree-toggle.js'; 79 | import '@vaadin/upload/src/vaadin-upload.js'; 80 | import '@vaadin/virtual-list/src/vaadin-virtual-list.js'; 81 | import 'Frontend/generated/jar-resources/virtualListConnector.js'; 82 | import '@vaadin/vaadin-lumo-styles/color-global.js'; 83 | import '@vaadin/vaadin-lumo-styles/typography-global.js'; 84 | import '@vaadin/vaadin-lumo-styles/sizing.js'; 85 | import '@vaadin/vaadin-lumo-styles/spacing.js'; 86 | import '@vaadin/vaadin-lumo-styles/style.js'; 87 | import '@vaadin/vaadin-lumo-styles/vaadin-iconset.js'; 88 | const loadOnDemand = (key) => { return Promise.resolve(0); } 89 | window.Vaadin = window.Vaadin || {}; 90 | window.Vaadin.Flow = window.Vaadin.Flow || {}; 91 | window.Vaadin.Flow.loadOnDemand = loadOnDemand; 92 | window.Vaadin.Flow.resetFocus = () => { 93 | let ae=document.activeElement; 94 | while(ae&&ae.shadowRoot) ae = ae.shadowRoot.activeElement; 95 | return !ae || ae.blur() || ae.focus() || true; 96 | } -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/flow/generated-flow-webcomponent-imports.js: -------------------------------------------------------------------------------- 1 | import { injectGlobalWebcomponentCss } from 'Frontend/generated/jar-resources/theme-util.js'; 2 | 3 | import '@vaadin/field-highlighter/src/vaadin-field-highlighter.js'; 4 | import '@vaadin/common-frontend/ConnectionIndicator.js'; 5 | import '@vaadin/polymer-legacy-adapter/style-modules.js'; 6 | import '@vaadin/accordion/src/vaadin-accordion.js'; 7 | import '@vaadin/details/src/vaadin-details.js'; 8 | import '@vaadin/accordion/src/vaadin-accordion-panel.js'; 9 | import '@vaadin/app-layout/src/vaadin-app-layout.js'; 10 | import '@vaadin/button/src/vaadin-button.js'; 11 | import '@vaadin/app-layout/src/vaadin-drawer-toggle.js'; 12 | import '@vaadin/avatar/src/vaadin-avatar.js'; 13 | import '@vaadin/avatar-group/src/vaadin-avatar-group.js'; 14 | import '@vaadin/checkbox/src/vaadin-checkbox.js'; 15 | import '@vaadin/checkbox-group/src/vaadin-checkbox-group.js'; 16 | import '@vaadin/combo-box/src/vaadin-combo-box.js'; 17 | import 'Frontend/generated/jar-resources/flow-component-renderer.js'; 18 | import 'Frontend/generated/jar-resources/comboBoxConnector.js'; 19 | import '@vaadin/multi-select-combo-box/src/vaadin-multi-select-combo-box.js'; 20 | import '@vaadin/confirm-dialog/src/vaadin-confirm-dialog.js'; 21 | import '@vaadin/context-menu/src/vaadin-context-menu.js'; 22 | import 'Frontend/generated/jar-resources/contextMenuConnector.js'; 23 | import 'Frontend/generated/jar-resources/contextMenuTargetConnector.js'; 24 | import '@vaadin/custom-field/src/vaadin-custom-field.js'; 25 | import '@vaadin/date-picker/src/vaadin-date-picker.js'; 26 | import 'Frontend/generated/jar-resources/datepickerConnector.js'; 27 | import '@vaadin/date-time-picker/src/vaadin-date-time-picker.js'; 28 | import '@vaadin/time-picker/src/vaadin-time-picker.js'; 29 | import 'Frontend/generated/jar-resources/vaadin-time-picker/timepickerConnector.js'; 30 | import '@vaadin/dialog/src/vaadin-dialog.js'; 31 | import 'Frontend/generated/jar-resources/dndConnector.js'; 32 | import '@vaadin/form-layout/src/vaadin-form-layout.js'; 33 | import '@vaadin/form-layout/src/vaadin-form-item.js'; 34 | import '@vaadin/grid/src/vaadin-grid-column-group.js'; 35 | import '@vaadin/grid/src/vaadin-grid.js'; 36 | import '@vaadin/grid/src/vaadin-grid-column.js'; 37 | import '@vaadin/grid/src/vaadin-grid-sorter.js'; 38 | import 'Frontend/generated/jar-resources/gridConnector.ts'; 39 | import '@vaadin/tooltip/src/vaadin-tooltip.js'; 40 | import 'Frontend/generated/jar-resources/vaadin-grid-flow-selection-column.js'; 41 | import '@vaadin/icon/src/vaadin-icon.js'; 42 | import '@vaadin/icons/vaadin-iconset.js'; 43 | import '@vaadin/list-box/src/vaadin-list-box.js'; 44 | import '@vaadin/item/src/vaadin-item.js'; 45 | import '@vaadin/login/src/vaadin-login-form.js'; 46 | import '@vaadin/login/src/vaadin-login-overlay.js'; 47 | import 'Frontend/generated/jar-resources/menubarConnector.js'; 48 | import '@vaadin/menu-bar/src/vaadin-menu-bar.js'; 49 | import '@vaadin/message-input/src/vaadin-message-input.js'; 50 | import 'Frontend/generated/jar-resources/messageListConnector.js'; 51 | import '@vaadin/message-list/src/vaadin-message-list.js'; 52 | import '@vaadin/notification/src/vaadin-notification.js'; 53 | import '@vaadin/horizontal-layout/src/vaadin-horizontal-layout.js'; 54 | import '@vaadin/scroller/src/vaadin-scroller.js'; 55 | import '@vaadin/vertical-layout/src/vaadin-vertical-layout.js'; 56 | import '@vaadin/popover/src/vaadin-popover.js'; 57 | import 'Frontend/generated/jar-resources/vaadin-popover/popover.ts'; 58 | import '@vaadin/progress-bar/src/vaadin-progress-bar.js'; 59 | import '@vaadin/radio-group/src/vaadin-radio-button.js'; 60 | import '@vaadin/radio-group/src/vaadin-radio-group.js'; 61 | import 'Frontend/generated/jar-resources/ReactRouterOutletElement.tsx'; 62 | import '@vaadin/select/src/vaadin-select.js'; 63 | import 'Frontend/generated/jar-resources/selectConnector.js'; 64 | import 'Frontend/generated/jar-resources/tooltip.ts'; 65 | import 'Frontend/generated/jar-resources/disableOnClickFunctions.js'; 66 | import '@vaadin/side-nav/src/vaadin-side-nav.js'; 67 | import '@vaadin/side-nav/src/vaadin-side-nav-item.js'; 68 | import '@vaadin/split-layout/src/vaadin-split-layout.js'; 69 | import '@vaadin/tabs/src/vaadin-tab.js'; 70 | import '@vaadin/tabsheet/src/vaadin-tabsheet.js'; 71 | import '@vaadin/tabs/src/vaadin-tabs.js'; 72 | import 'Frontend/generated/jar-resources/vaadin-big-decimal-field.js'; 73 | import '@vaadin/email-field/src/vaadin-email-field.js'; 74 | import '@vaadin/integer-field/src/vaadin-integer-field.js'; 75 | import '@vaadin/number-field/src/vaadin-number-field.js'; 76 | import '@vaadin/password-field/src/vaadin-password-field.js'; 77 | import '@vaadin/text-area/src/vaadin-text-area.js'; 78 | import '@vaadin/text-field/src/vaadin-text-field.js'; 79 | import 'Frontend/generated/jar-resources/lit-renderer.ts'; 80 | import '@vaadin/grid/src/vaadin-grid-tree-toggle.js'; 81 | import '@vaadin/upload/src/vaadin-upload.js'; 82 | import '@vaadin/virtual-list/src/vaadin-virtual-list.js'; 83 | import 'Frontend/generated/jar-resources/virtualListConnector.js'; 84 | import '@vaadin/vaadin-lumo-styles/sizing.js'; 85 | import '@vaadin/vaadin-lumo-styles/spacing.js'; 86 | import '@vaadin/vaadin-lumo-styles/style.js'; 87 | import '@vaadin/vaadin-lumo-styles/vaadin-iconset.js'; 88 | const loadOnDemand = (key) => { return Promise.resolve(0); } 89 | window.Vaadin = window.Vaadin || {}; 90 | window.Vaadin.Flow = window.Vaadin.Flow || {}; 91 | window.Vaadin.Flow.loadOnDemand = loadOnDemand; 92 | window.Vaadin.Flow.resetFocus = () => { 93 | let ae=document.activeElement; 94 | while(ae&&ae.shadowRoot) ae = ae.shadowRoot.activeElement; 95 | return !ae || ae.blur() || ae.focus() || true; 96 | } -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/Flow.d.ts: -------------------------------------------------------------------------------- 1 | export interface FlowConfig { 2 | imports?: () => Promise; 3 | } 4 | interface AppConfig { 5 | productionMode: boolean; 6 | appId: string; 7 | uidl: any; 8 | } 9 | interface AppInitResponse { 10 | appConfig: AppConfig; 11 | pushScript?: string; 12 | } 13 | interface Router { 14 | render: (ctx: NavigationParameters, shouldUpdateHistory: boolean) => Promise; 15 | } 16 | interface HTMLRouterContainer extends HTMLElement { 17 | onBeforeEnter?: (ctx: NavigationParameters, cmd: PreventAndRedirectCommands, router: Router) => void | Promise; 18 | onBeforeLeave?: (ctx: NavigationParameters, cmd: PreventCommands, router: Router) => void | Promise; 19 | serverConnected?: (cancel: boolean, url?: NavigationParameters) => void; 20 | serverPaused?: () => void; 21 | } 22 | interface FlowRoute { 23 | action: (params: NavigationParameters) => Promise; 24 | path: string; 25 | } 26 | export interface NavigationParameters { 27 | pathname: string; 28 | search?: string; 29 | } 30 | export interface PreventCommands { 31 | prevent: () => any; 32 | continue?: () => any; 33 | } 34 | export interface PreventAndRedirectCommands extends PreventCommands { 35 | redirect: (route: string) => any; 36 | } 37 | /** 38 | * Client API for flow UI operations. 39 | */ 40 | export declare class Flow { 41 | config: FlowConfig; 42 | response?: AppInitResponse; 43 | pathname: string; 44 | container: HTMLRouterContainer; 45 | private isActive; 46 | private baseRegex; 47 | private appShellTitle; 48 | private navigation; 49 | constructor(config?: FlowConfig); 50 | /** 51 | * Return a `route` object for vaadin-router in an one-element array. 52 | * 53 | * The `FlowRoute` object `path` property handles any route, 54 | * and the `action` returns the flow container without updating the content, 55 | * delaying the actual Flow server call to the `onBeforeEnter` phase. 56 | * 57 | * This is a specific API for its use with `vaadin-router`. 58 | */ 59 | get serverSideRoutes(): [FlowRoute]; 60 | loadingStarted(): void; 61 | loadingFinished(): void; 62 | private get action(); 63 | private flowLeave; 64 | private flowNavigate; 65 | private getFlowRoutePath; 66 | private getFlowRouteQuery; 67 | private flowInit; 68 | private loadScript; 69 | private findNonce; 70 | private injectAppIdScript; 71 | private flowInitClient; 72 | private flowInitUi; 73 | private addConnectionIndicator; 74 | private offlineStubAction; 75 | private isFlowClientLoaded; 76 | } 77 | export {}; 78 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/FlowBootstrap.d.ts: -------------------------------------------------------------------------------- 1 | export const init: (appInitResponse: any) => void; 2 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/FlowClient.d.ts: -------------------------------------------------------------------------------- 1 | export const init: () => void; 2 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/ReactRouterOutletElement.tsx: -------------------------------------------------------------------------------- 1 | import { Outlet } from 'react-router-dom'; 2 | import { ReactAdapterElement } from "Frontend/generated/flow/ReactAdapter.js"; 3 | import React from "react"; 4 | 5 | class ReactRouterOutletElement extends ReactAdapterElement { 6 | protected render(): React.ReactElement | null { 7 | return ; 8 | } 9 | 10 | } 11 | 12 | customElements.define('react-router-outlet', ReactRouterOutletElement); 13 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/contextMenuConnector.js: -------------------------------------------------------------------------------- 1 | function getContainer(appId, nodeId) { 2 | try { 3 | return window.Vaadin.Flow.clients[appId].getByNodeId(nodeId); 4 | } catch (error) { 5 | console.error('Could not get node %s from app %s', nodeId, appId); 6 | console.error(error); 7 | } 8 | } 9 | 10 | /** 11 | * Initializes the connector for a context menu element. 12 | * 13 | * @param {HTMLElement} contextMenu 14 | * @param {string} appId 15 | */ 16 | function initLazy(contextMenu, appId) { 17 | if (contextMenu.$connector) { 18 | return; 19 | } 20 | 21 | contextMenu.$connector = { 22 | /** 23 | * Generates and assigns the items to the context menu. 24 | * 25 | * @param {number} nodeId 26 | */ 27 | generateItems(nodeId) { 28 | const items = generateItemsTree(appId, nodeId); 29 | 30 | contextMenu.items = items; 31 | } 32 | }; 33 | } 34 | 35 | /** 36 | * Generates an items tree compatible with the context-menu web component 37 | * by traversing the given Flow DOM tree of context menu item nodes 38 | * whose root node is identified by the `nodeId` argument. 39 | * 40 | * The app id is required to access the store of Flow DOM nodes. 41 | * 42 | * @param {string} appId 43 | * @param {number} nodeId 44 | */ 45 | function generateItemsTree(appId, nodeId) { 46 | const container = getContainer(appId, nodeId); 47 | if (!container) { 48 | return; 49 | } 50 | 51 | return Array.from(container.children).map((child) => { 52 | const item = { 53 | component: child, 54 | checked: child._checked, 55 | keepOpen: child._keepOpen, 56 | className: child.className, 57 | theme: child.__theme 58 | }; 59 | // Do not hardcode tag name to allow `vaadin-menu-bar-item` 60 | if (child._hasVaadinItemMixin && child._containerNodeId) { 61 | item.children = generateItemsTree(appId, child._containerNodeId); 62 | } 63 | child._item = item; 64 | return item; 65 | }); 66 | } 67 | 68 | /** 69 | * Sets the checked state for a context menu item. 70 | * 71 | * This method is supposed to be called when the context menu item is closed, 72 | * so there is no need for triggering a re-render eagarly. 73 | * 74 | * @param {HTMLElement} component 75 | * @param {boolean} checked 76 | */ 77 | function setChecked(component, checked) { 78 | if (component._item) { 79 | component._item.checked = checked; 80 | 81 | // Set the attribute in the connector to show the checkmark 82 | // without having to re-render the whole menu while opened. 83 | if (component._item.keepOpen) { 84 | component.toggleAttribute('menu-item-checked', checked); 85 | } 86 | } 87 | } 88 | 89 | /** 90 | * Sets the keep open state for a context menu item. 91 | * 92 | * @param {HTMLElement} component 93 | * @param {boolean} keepOpen 94 | */ 95 | function setKeepOpen(component, keepOpen) { 96 | if (component._item) { 97 | component._item.keepOpen = keepOpen; 98 | } 99 | } 100 | 101 | /** 102 | * Sets the theme for a context menu item. 103 | * 104 | * This method is supposed to be called when the context menu item is closed, 105 | * so there is no need for triggering a re-render eagarly. 106 | * 107 | * @param {HTMLElement} component 108 | * @param {string | undefined | null} theme 109 | */ 110 | function setTheme(component, theme) { 111 | if (component._item) { 112 | component._item.theme = theme; 113 | } 114 | } 115 | 116 | window.Vaadin.Flow.contextMenuConnector = { 117 | initLazy, 118 | generateItemsTree, 119 | setChecked, 120 | setKeepOpen, 121 | setTheme 122 | }; 123 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/contextMenuTargetConnector.js: -------------------------------------------------------------------------------- 1 | import * as Gestures from '@vaadin/component-base/src/gestures.js'; 2 | 3 | function init(target) { 4 | if (target.$contextMenuTargetConnector) { 5 | return; 6 | } 7 | 8 | target.$contextMenuTargetConnector = { 9 | openOnHandler(e) { 10 | // used by Grid to prevent context menu on selection column click 11 | if (target.preventContextMenu && target.preventContextMenu(e)) { 12 | return; 13 | } 14 | e.preventDefault(); 15 | e.stopPropagation(); 16 | this.$contextMenuTargetConnector.openEvent = e; 17 | let detail = {}; 18 | if (target.getContextMenuBeforeOpenDetail) { 19 | detail = target.getContextMenuBeforeOpenDetail(e); 20 | } 21 | target.dispatchEvent( 22 | new CustomEvent('vaadin-context-menu-before-open', { 23 | detail: detail 24 | }) 25 | ); 26 | }, 27 | 28 | updateOpenOn(eventType) { 29 | this.removeListener(); 30 | this.openOnEventType = eventType; 31 | 32 | customElements.whenDefined('vaadin-context-menu').then(() => { 33 | if (Gestures.gestures[eventType]) { 34 | Gestures.addListener(target, eventType, this.openOnHandler); 35 | } else { 36 | target.addEventListener(eventType, this.openOnHandler); 37 | } 38 | }); 39 | }, 40 | 41 | removeListener() { 42 | if (this.openOnEventType) { 43 | if (Gestures.gestures[this.openOnEventType]) { 44 | Gestures.removeListener(target, this.openOnEventType, this.openOnHandler); 45 | } else { 46 | target.removeEventListener(this.openOnEventType, this.openOnHandler); 47 | } 48 | } 49 | }, 50 | 51 | openMenu(contextMenu) { 52 | contextMenu.open(this.openEvent); 53 | }, 54 | 55 | removeConnector() { 56 | this.removeListener(); 57 | target.$contextMenuTargetConnector = undefined; 58 | } 59 | }; 60 | } 61 | 62 | window.Vaadin.Flow.contextMenuTargetConnector = { init }; 63 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/copilot.js: -------------------------------------------------------------------------------- 1 | import "./copilot/copilot-B_g-uHXF.js"; 2 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/copilot/base-panel-C9ezFash.js: -------------------------------------------------------------------------------- 1 | import { M as t, j as n, b as a } from "./copilot-B_g-uHXF.js"; 2 | class i extends t { 3 | constructor() { 4 | super(...arguments), this.eventBusRemovers = [], this.messageHandlers = {}, this.handleESC = (e) => { 5 | n.active && e.key === "Escape" && typeof this.close == "function" && this.close(); 6 | }; 7 | } 8 | createRenderRoot() { 9 | return this; 10 | } 11 | onEventBus(e, s) { 12 | this.eventBusRemovers.push(a.on(e, s)); 13 | } 14 | connectedCallback() { 15 | super.connectedCallback(), this.addESCListener(); 16 | } 17 | disconnectedCallback() { 18 | super.disconnectedCallback(), this.eventBusRemovers.forEach((e) => e()), this.removeESCListener(); 19 | } 20 | addESCListener() { 21 | document.addEventListener("keydown", this.handleESC); 22 | } 23 | removeESCListener() { 24 | document.removeEventListener("keydown", this.handleESC); 25 | } 26 | onCommand(e, s) { 27 | this.messageHandlers[e] = s; 28 | } 29 | handleMessage(e) { 30 | return this.messageHandlers[e.command] ? (this.messageHandlers[e.command].call(this, e), !0) : !1; 31 | } 32 | } 33 | export { 34 | i as B 35 | }; 36 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/copilot/copilot-features-plugin-CcvV6-I_.js: -------------------------------------------------------------------------------- 1 | import { x as r, j as d, Z as g, a1 as c, a2 as f, n as u } from "./copilot-B_g-uHXF.js"; 2 | import { B as h } from "./base-panel-C9ezFash.js"; 3 | import { i as m } from "./icons-x5khyqlC.js"; 4 | const v = "copilot-features-panel{padding:var(--space-100);font:var(--font-xsmall);display:grid;grid-template-columns:auto 1fr;gap:var(--space-50);height:auto}copilot-features-panel a{display:flex;align-items:center;gap:var(--space-50);white-space:nowrap}copilot-features-panel a svg{height:12px;width:12px;min-height:12px;min-width:12px}"; 5 | var b = Object.getOwnPropertyDescriptor, w = (e, t, a, n) => { 6 | for (var o = n > 1 ? void 0 : n ? b(t, a) : t, s = e.length - 1, i; s >= 0; s--) 7 | (i = e[s]) && (o = i(o) || o); 8 | return o; 9 | }; 10 | const l = window.Vaadin.devTools; 11 | let p = class extends h { 12 | render() { 13 | return r` 16 | ${d.featureFlags.map( 17 | (e) => r` 18 | this.toggleFeatureFlag(t, e)}> 22 | 23 | learn more ${m.share} 26 | ` 27 | )}`; 28 | } 29 | toggleFeatureFlag(e, t) { 30 | const a = e.target.checked; 31 | g("use-feature", { source: "toggle", enabled: a, id: t.id }), l.frontendConnection ? (l.frontendConnection.send("setFeature", { featureId: t.id, enabled: a }), c({ 32 | type: f.INFORMATION, 33 | message: `“${t.title}” ${a ? "enabled" : "disabled"}`, 34 | details: t.requiresServerRestart ? "This feature requires a server restart" : void 0, 35 | dismissId: `feature${t.id}${a ? "Enabled" : "Disabled"}` 36 | })) : l.log("error", `Unable to toggle feature ${t.title}: No server connection available`); 37 | } 38 | }; 39 | p = w([ 40 | u("copilot-features-panel") 41 | ], p); 42 | const $ = { 43 | header: "Features", 44 | expanded: !1, 45 | panelOrder: 35, 46 | panel: "right", 47 | floating: !1, 48 | tag: "copilot-features-panel", 49 | helpUrl: "https://vaadin.com/docs/latest/flow/configuration/feature-flags" 50 | }, x = { 51 | init(e) { 52 | e.addPanel($); 53 | } 54 | }; 55 | window.Vaadin.copilot.plugins.push(x); 56 | export { 57 | p as CopilotFeaturesPanel 58 | }; 59 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/copilot/copilot-shortcuts-plugin-B1zChRPf.js: -------------------------------------------------------------------------------- 1 | import { n as f, b as c, x as i, F as g, W as m, N as e, z as b } from "./copilot-B_g-uHXF.js"; 2 | import { B as $ } from "./base-panel-C9ezFash.js"; 3 | import { i as a } from "./icons-x5khyqlC.js"; 4 | const v = 'copilot-shortcuts-panel{display:flex;flex-direction:column;padding:var(--space-150)}copilot-shortcuts-panel h3{font:var(--font-xsmall-semibold);margin-bottom:var(--space-100);margin-top:0}copilot-shortcuts-panel h3:not(:first-of-type){margin-top:var(--space-200)}copilot-shortcuts-panel ul{display:flex;flex-direction:column;list-style:none;margin:0;padding:0}copilot-shortcuts-panel ul li{display:flex;align-items:center;gap:var(--space-50);position:relative}copilot-shortcuts-panel ul li:not(:last-of-type):before{border-bottom:1px dashed var(--border-color);content:"";inset:auto 0 0 calc(var(--size-m) + var(--space-50));position:absolute}copilot-shortcuts-panel ul li span:has(svg){align-items:center;display:flex;height:var(--size-m);justify-content:center;width:var(--size-m)}copilot-shortcuts-panel .kbds{margin-inline-start:auto}copilot-shortcuts-panel kbd{align-items:center;border:1px solid var(--border-color);border-radius:var(--radius-2);box-sizing:border-box;display:inline-flex;font-family:var(--font-family);font-size:var(--font-size-1);line-height:var(--line-height-1);padding:0 var(--space-50)}', u = window.Vaadin.copilot.tree; 5 | if (!u) 6 | throw new Error("Tried to access copilot tree before it was initialized."); 7 | var y = Object.getOwnPropertyDescriptor, w = (s, l, h, p) => { 8 | for (var o = p > 1 ? void 0 : p ? y(l, h) : l, n = s.length - 1, r; n >= 0; n--) 9 | (r = s[n]) && (o = r(o) || o); 10 | return o; 11 | }; 12 | let d = class extends $ { 13 | constructor() { 14 | super(), this.onTreeUpdated = () => { 15 | this.requestUpdate(); 16 | }; 17 | } 18 | connectedCallback() { 19 | super.connectedCallback(), c.on("copilot-tree-created", this.onTreeUpdated); 20 | } 21 | disconnectedCallback() { 22 | super.disconnectedCallback(), c.off("copilot-tree-created", this.onTreeUpdated); 23 | } 24 | render() { 25 | const s = u.hasFlowComponents(); 26 | return i` 29 |

Global

30 |
    31 |
  • 32 | ${a.vaadinLogo} 33 | Copilot 34 | ${t(e.toggleCopilot)} 35 |
  • 36 |
  • 37 | ${a.terminal} 38 | Command window 39 | ${t(e.toggleCommandWindow)} 40 |
  • 41 |
  • 42 | ${a.flipBack} 43 | Undo 44 | ${t(e.undo)} 45 |
  • 46 |
  • 47 | ${a.flipForward} 48 | Redo 49 | ${t(e.redo)} 50 |
  • 51 |
52 |

Selected component

53 |
    54 |
  • 55 | ${a.fileCodeAlt} 56 | Go to source 57 | ${t(e.goToSource)} 58 |
  • 59 | ${s ? i`
  • 60 | ${a.code} 61 | Go to attach source 62 | ${t(e.goToAttachSource)} 63 |
  • ` : g} 64 |
  • 65 | ${a.copy} 66 | Copy 67 | ${t(e.copy)} 68 |
  • 69 |
  • 70 | ${a.clipboard} 71 | Paste 72 | ${t(e.paste)} 73 |
  • 74 |
  • 75 | ${a.copyAlt} 76 | Duplicate 77 | ${t(e.duplicate)} 78 |
  • 79 |
  • 80 | ${a.userUp} 81 | Select parent 82 | ${t(e.selectParent)} 83 |
  • 84 |
  • 85 | ${a.userLeft} 86 | Select previous sibling 87 | ${t(e.selectPreviousSibling)} 88 |
  • 89 |
  • 90 | ${a.userRight} 91 | Select first child / next sibling 92 | ${t(e.selectNextSibling)} 93 |
  • 94 |
  • 95 | ${a.trash} 96 | Delete 97 | ${t(e.delete)} 98 |
  • 99 |
`; 100 | } 101 | }; 102 | d = w([ 103 | f("copilot-shortcuts-panel") 104 | ], d); 105 | function t(s) { 106 | return i`${m(s)}`; 107 | } 108 | const x = b({ 109 | header: "Keyboard Shortcuts", 110 | tag: "copilot-shortcuts-panel", 111 | width: 400, 112 | height: 550, 113 | floatingPosition: { 114 | top: 50, 115 | left: 50 116 | } 117 | }), C = { 118 | init(s) { 119 | s.addPanel(x); 120 | } 121 | }; 122 | window.Vaadin.copilot.plugins.push(C); 123 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/copilot/early-project-state-CqEloDes.js: -------------------------------------------------------------------------------- 1 | const e = window.Vaadin.copilot._earlyProjectState; 2 | if (!e) 3 | throw new Error("Tried to access early project state before it was initialized."); 4 | export { 5 | e 6 | }; 7 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/copilot/overlay-monkeypatch-CfGi1TGf.js: -------------------------------------------------------------------------------- 1 | import { P as c } from "./copilot-B_g-uHXF.js"; 2 | /** 3 | * @license 4 | * Copyright 2017 Google LLC 5 | * SPDX-License-Identifier: BSD-3-Clause 6 | */ 7 | const d = (e, a, t) => (t.configurable = !0, t.enumerable = !0, Reflect.decorate && typeof a != "object" && Object.defineProperty(e, a, t), t); 8 | /** 9 | * @license 10 | * Copyright 2017 Google LLC 11 | * SPDX-License-Identifier: BSD-3-Clause 12 | */ 13 | function h(e, a) { 14 | return (t, o, v) => { 15 | const i = (l) => l.renderRoot?.querySelector(e) ?? null; 16 | return d(t, o, { get() { 17 | return i(this); 18 | } }); 19 | }; 20 | } 21 | function u(e) { 22 | e.querySelectorAll( 23 | "vaadin-context-menu, vaadin-menu-bar, vaadin-menu-bar-submenu, vaadin-select, vaadin-combo-box, vaadin-tooltip, vaadin-dialog, vaadin-multi-select-combo-box, vaadin-popover" 24 | ).forEach((a) => { 25 | a?.$?.comboBox && (a = a.$.comboBox); 26 | let t = a.shadowRoot?.querySelector( 27 | `${a.localName}-overlay, ${a.localName}-submenu, vaadin-menu-bar-overlay` 28 | ); 29 | t?.localName === "vaadin-menu-bar-submenu" && (t = t.shadowRoot.querySelector("vaadin-menu-bar-overlay")), t ? t._attachOverlay = n.bind(t) : a.$?.overlay && (a.$.overlay._attachOverlay = n.bind(a.$.overlay)); 30 | }); 31 | } 32 | function r() { 33 | return document.querySelector(`${c}main`).shadowRoot; 34 | } 35 | const m = () => Array.from(r().children).filter((a) => a._hasOverlayStackMixin && !a.hasAttribute("closing")).sort((a, t) => a.__zIndex - t.__zIndex || 0), s = (e) => e === m().pop(); 36 | function n() { 37 | const e = this; 38 | e._placeholder = document.createComment("vaadin-overlay-placeholder"), e.parentNode.insertBefore(e._placeholder, e), r().appendChild(e), e.hasOwnProperty("_last") || Object.defineProperty(e, "_last", { 39 | // Only returns odd die sides 40 | get() { 41 | return s(this); 42 | } 43 | }), e.bringToFront(), requestAnimationFrame(() => u(e)); 44 | } 45 | export { 46 | h as e, 47 | u as m 48 | }; 49 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/copilot/state-DDML0umE.js: -------------------------------------------------------------------------------- 1 | import { aa as u, ab as l } from "./copilot-B_g-uHXF.js"; 2 | /** 3 | * @license 4 | * Copyright 2017 Google LLC 5 | * SPDX-License-Identifier: BSD-3-Clause 6 | */ 7 | const p = { attribute: !0, type: String, converter: l, reflect: !1, hasChanged: u }, d = (t = p, n, e) => { 8 | const { kind: o, metadata: s } = e; 9 | let a = globalThis.litPropertyMetadata.get(s); 10 | if (a === void 0 && globalThis.litPropertyMetadata.set(s, a = /* @__PURE__ */ new Map()), a.set(e.name, t), o === "accessor") { 11 | const { name: r } = e; 12 | return { set(i) { 13 | const c = n.get.call(this); 14 | n.set.call(this, i), this.requestUpdate(r, c, t); 15 | }, init(i) { 16 | return i !== void 0 && this.P(r, void 0, t), i; 17 | } }; 18 | } 19 | if (o === "setter") { 20 | const { name: r } = e; 21 | return function(i) { 22 | const c = this[r]; 23 | n.call(this, i), this.requestUpdate(r, c, t); 24 | }; 25 | } 26 | throw Error("Unsupported decorator location: " + o); 27 | }; 28 | function h(t) { 29 | return (n, e) => typeof e == "object" ? d(t, n, e) : ((o, s, a) => { 30 | const r = s.hasOwnProperty(a); 31 | return s.constructor.createProperty(a, r ? { ...o, wrapped: !0 } : o), r ? Object.getOwnPropertyDescriptor(s, a) : void 0; 32 | })(t, n, e); 33 | } 34 | /** 35 | * @license 36 | * Copyright 2017 Google LLC 37 | * SPDX-License-Identifier: BSD-3-Clause 38 | */ 39 | function b(t) { 40 | return h({ ...t, state: !0, attribute: !1 }); 41 | } 42 | export { 43 | h as n, 44 | b as r 45 | }; 46 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/disableOnClickFunctions.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('click', (event) => { 2 | const target = event.composedPath().find((node) => node.hasAttribute && node.hasAttribute('disableonclick')); 3 | if (target) { 4 | target.disabled = true; 5 | } 6 | }); 7 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/dndConnector.js: -------------------------------------------------------------------------------- 1 | window.Vaadin = window.Vaadin || {}; 2 | window.Vaadin.Flow = window.Vaadin.Flow || {}; 3 | window.Vaadin.Flow.dndConnector = { 4 | __ondragenterListener: function (event) { 5 | // TODO filter by data type 6 | // TODO prevent dropping on itself (by default) 7 | const effect = event.currentTarget['__dropEffect']; 8 | if (!event.currentTarget.hasAttribute('disabled')) { 9 | if (effect) { 10 | event.dataTransfer.dropEffect = effect; 11 | } 12 | 13 | if (effect !== 'none') { 14 | /* #7108: if drag moves on top of drop target's children, first another ondragenter event 15 | * is fired and then a ondragleave event. This happens again once the drag 16 | * moves on top of another children, or back on top of the drop target element. 17 | * Thus need to "cancel" the following ondragleave, to not remove class name. 18 | * Drop event will happen even when dropped to a child element. */ 19 | if (event.currentTarget.classList.contains('v-drag-over-target')) { 20 | event.currentTarget['__skip-leave'] = true; 21 | } else { 22 | event.currentTarget.classList.add('v-drag-over-target'); 23 | } 24 | // enables browser specific pseudo classes (at least FF) 25 | event.preventDefault(); 26 | event.stopPropagation(); // don't let parents know 27 | } 28 | } 29 | }, 30 | 31 | __ondragoverListener: function (event) { 32 | // TODO filter by data type 33 | // TODO filter by effectAllowed != dropEffect due to Safari & IE11 ? 34 | if (!event.currentTarget.hasAttribute('disabled')) { 35 | const effect = event.currentTarget['__dropEffect']; 36 | if (effect) { 37 | event.dataTransfer.dropEffect = effect; 38 | } 39 | // allows the drop && don't let parents know 40 | event.preventDefault(); 41 | event.stopPropagation(); 42 | } 43 | }, 44 | 45 | __ondragleaveListener: function (event) { 46 | if (event.currentTarget['__skip-leave']) { 47 | event.currentTarget['__skip-leave'] = false; 48 | } else { 49 | event.currentTarget.classList.remove('v-drag-over-target'); 50 | } 51 | // #7109 need to stop or any parent drop target might not get highlighted, 52 | // as ondragenter for it is fired before the child gets dragleave. 53 | event.stopPropagation(); 54 | }, 55 | 56 | __ondropListener: function (event) { 57 | const effect = event.currentTarget['__dropEffect']; 58 | if (effect) { 59 | event.dataTransfer.dropEffect = effect; 60 | } 61 | event.currentTarget.classList.remove('v-drag-over-target'); 62 | // prevent browser handling && don't let parents know 63 | event.preventDefault(); 64 | event.stopPropagation(); 65 | }, 66 | 67 | updateDropTarget: function (element) { 68 | if (element['__active']) { 69 | element.addEventListener('dragenter', this.__ondragenterListener, false); 70 | element.addEventListener('dragover', this.__ondragoverListener, false); 71 | element.addEventListener('dragleave', this.__ondragleaveListener, false); 72 | element.addEventListener('drop', this.__ondropListener, false); 73 | } else { 74 | element.removeEventListener('dragenter', this.__ondragenterListener, false); 75 | element.removeEventListener('dragover', this.__ondragoverListener, false); 76 | element.removeEventListener('dragleave', this.__ondragleaveListener, false); 77 | element.removeEventListener('drop', this.__ondropListener, false); 78 | element.classList.remove('v-drag-over-target'); 79 | } 80 | }, 81 | 82 | /** DRAG SOURCE METHODS: */ 83 | 84 | __dragstartListener: function (event) { 85 | event.stopPropagation(); 86 | event.dataTransfer.setData('text/plain', ''); 87 | if (event.currentTarget.hasAttribute('disabled')) { 88 | event.preventDefault(); 89 | } else { 90 | if (event.currentTarget['__effectAllowed']) { 91 | event.dataTransfer.effectAllowed = event.currentTarget['__effectAllowed']; 92 | } 93 | event.currentTarget.classList.add('v-dragged'); 94 | } 95 | if(event.currentTarget.__dragImage) { 96 | if(event.currentTarget.__dragImage.style.display === "none") { 97 | event.currentTarget.__dragImage.style.display = "block"; 98 | event.currentTarget.classList.add('shown'); 99 | } 100 | event.dataTransfer.setDragImage( 101 | event.currentTarget.__dragImage, 102 | event.currentTarget.__dragImageOffsetX, 103 | event.currentTarget.__dragImageOffsetY); 104 | } 105 | }, 106 | 107 | __dragendListener: function (event) { 108 | event.currentTarget.classList.remove('v-dragged'); 109 | if(event.currentTarget.classList.contains('shown')) { 110 | event.currentTarget.classList.remove('shown'); 111 | event.currentTarget.__dragImage.style.display = "none"; 112 | } 113 | }, 114 | 115 | updateDragSource: function (element) { 116 | if (element['draggable']) { 117 | element.addEventListener('dragstart', this.__dragstartListener, false); 118 | element.addEventListener('dragend', this.__dragendListener, false); 119 | } else { 120 | element.removeEventListener('dragstart', this.__dragstartListener, false); 121 | element.removeEventListener('dragend', this.__dragendListener, false); 122 | } 123 | }, 124 | 125 | setDragImage: function (dragImage, offsetX, offsetY, dragSource) { 126 | dragSource.__dragImage = dragImage; 127 | dragSource.__dragImageOffsetX = offsetX; 128 | dragSource.__dragImageOffsetY = offsetY; 129 | } 130 | }; 131 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/flow-component-directive.js: -------------------------------------------------------------------------------- 1 | import { noChange } from 'lit'; 2 | import { directive, PartType } from 'lit/directive.js'; 3 | import { AsyncDirective } from 'lit/async-directive.js'; 4 | 5 | class FlowComponentDirective extends AsyncDirective { 6 | constructor(partInfo) { 7 | super(partInfo); 8 | if (partInfo.type !== PartType.CHILD) { 9 | throw new Error(`${this.constructor.directiveName}() can only be used in child bindings`); 10 | } 11 | } 12 | 13 | update(part, [appid, nodeid]) { 14 | this.updateContent(part, appid, nodeid); 15 | return noChange; 16 | } 17 | 18 | updateContent(part, appid, nodeid) { 19 | const { parentNode, startNode } = part; 20 | this.__parentNode = parentNode; 21 | 22 | const hasNewNodeId = nodeid !== undefined && nodeid !== null; 23 | const newNode = hasNewNodeId ? this.getNewNode(appid, nodeid) : null; 24 | const oldNode = this.getOldNode(part); 25 | 26 | clearTimeout(this.__parentNode.__nodeRetryTimeout); 27 | 28 | if (hasNewNodeId && !newNode) { 29 | // If the node is not found, try again later. 30 | this.__parentNode.__nodeRetryTimeout = setTimeout(() => this.updateContent(part, appid, nodeid)); 31 | } else if (oldNode === newNode) { 32 | return; 33 | } else if (oldNode && newNode) { 34 | parentNode.replaceChild(newNode, oldNode); 35 | } else if (oldNode) { 36 | parentNode.removeChild(oldNode); 37 | } else if (newNode) { 38 | startNode.after(newNode); 39 | } 40 | } 41 | 42 | getNewNode(appid, nodeid) { 43 | return window.Vaadin.Flow.clients[appid].getByNodeId(nodeid); 44 | } 45 | 46 | getOldNode(part) { 47 | const { startNode, endNode } = part; 48 | if (startNode.nextSibling === endNode) { 49 | return; 50 | } 51 | return startNode.nextSibling; 52 | } 53 | 54 | disconnected() { 55 | clearTimeout(this.__parentNode.__nodeRetryTimeout); 56 | } 57 | } 58 | 59 | /** 60 | * Renders the given flow component node. 61 | * 62 | * WARNING: This directive is not intended for public use. 63 | * 64 | * @param {string} appid 65 | * @param {number} nodeid 66 | * @private 67 | */ 68 | export const flowComponentDirective = directive(FlowComponentDirective); 69 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/flow-component-renderer.js: -------------------------------------------------------------------------------- 1 | import '@polymer/polymer/lib/elements/dom-if.js'; 2 | import { html } from '@polymer/polymer/lib/utils/html-tag.js'; 3 | import { Debouncer } from '@polymer/polymer/lib/utils/debounce.js'; 4 | import { idlePeriod } from '@polymer/polymer/lib/utils/async.js'; 5 | import { PolymerElement } from '@polymer/polymer/polymer-element.js'; 6 | import { flowComponentDirective } from './flow-component-directive.js'; 7 | import { render, html as litHtml } from 'lit'; 8 | 9 | /** 10 | * Returns the requested node in a form suitable for Lit template interpolation. 11 | * @param {string} appid 12 | * @param {number} nodeid 13 | * @returns {any} a Lit directive 14 | */ 15 | function getNode(appid, nodeid) { 16 | return flowComponentDirective(appid, nodeid); 17 | } 18 | 19 | /** 20 | * Sets the nodes defined by the given node ids as the child nodes of the 21 | * given root element. 22 | * @param {string} appid 23 | * @param {number[]} nodeIds 24 | * @param {Element} root 25 | */ 26 | function setChildNodes(appid, nodeIds, root) { 27 | render(litHtml`${nodeIds.map((id) => flowComponentDirective(appid, id))}`, root); 28 | } 29 | 30 | /** 31 | * SimpleElementBindingStrategy::addChildren uses insertBefore to add child 32 | * elements to the container. When the children are manually placed under 33 | * another element, the call to insertBefore can occasionally fail due to 34 | * an invalid reference node. 35 | * 36 | * This is a temporary workaround which patches the container's native API 37 | * to not fail when called with invalid arguments. 38 | */ 39 | function patchVirtualContainer(container) { 40 | const originalInsertBefore = container.insertBefore; 41 | 42 | container.insertBefore = function (newNode, referenceNode) { 43 | if (referenceNode && referenceNode.parentNode === this) { 44 | return originalInsertBefore.call(this, newNode, referenceNode); 45 | } else { 46 | return originalInsertBefore.call(this, newNode, null); 47 | } 48 | }; 49 | } 50 | 51 | window.Vaadin ||= {}; 52 | window.Vaadin.FlowComponentHost ||= { patchVirtualContainer, getNode, setChildNodes }; 53 | 54 | class FlowComponentRenderer extends PolymerElement { 55 | static get template() { 56 | return html` 57 | 68 | 69 | `; 70 | } 71 | 72 | static get is() { 73 | return 'flow-component-renderer'; 74 | } 75 | static get properties() { 76 | return { 77 | nodeid: Number, 78 | appid: String 79 | }; 80 | } 81 | static get observers() { 82 | return ['_attachRenderedComponentIfAble(appid, nodeid)']; 83 | } 84 | 85 | ready() { 86 | super.ready(); 87 | this.addEventListener('click', function (event) { 88 | if (this.firstChild && typeof this.firstChild.click === 'function' && event.target === this) { 89 | event.stopPropagation(); 90 | this.firstChild.click(); 91 | } 92 | }); 93 | this.addEventListener('animationend', this._onAnimationEnd); 94 | } 95 | 96 | _asyncAttachRenderedComponentIfAble() { 97 | this._debouncer = Debouncer.debounce(this._debouncer, idlePeriod, () => this._attachRenderedComponentIfAble()); 98 | } 99 | 100 | _attachRenderedComponentIfAble() { 101 | if (this.appid == null) { 102 | return; 103 | } 104 | if (this.nodeid == null) { 105 | if (this.firstChild) { 106 | this.removeChild(this.firstChild); 107 | } 108 | return; 109 | } 110 | const renderedComponent = this._getRenderedComponent(); 111 | if (this.firstChild) { 112 | if (!renderedComponent) { 113 | this._asyncAttachRenderedComponentIfAble(); 114 | } else if (this.firstChild !== renderedComponent) { 115 | this.replaceChild(renderedComponent, this.firstChild); 116 | this._defineFocusTarget(); 117 | this.onComponentRendered(); 118 | } else { 119 | this._defineFocusTarget(); 120 | this.onComponentRendered(); 121 | } 122 | } else { 123 | if (renderedComponent) { 124 | this.appendChild(renderedComponent); 125 | this._defineFocusTarget(); 126 | this.onComponentRendered(); 127 | } else { 128 | this._asyncAttachRenderedComponentIfAble(); 129 | } 130 | } 131 | } 132 | 133 | _getRenderedComponent() { 134 | try { 135 | return window.Vaadin.Flow.clients[this.appid].getByNodeId(this.nodeid); 136 | } catch (error) { 137 | console.error('Could not get node %s from app %s', this.nodeid, this.appid); 138 | console.error(error); 139 | } 140 | return null; 141 | } 142 | 143 | onComponentRendered() { 144 | // subclasses can override this method to execute custom logic on resize 145 | } 146 | 147 | /* Setting the `focus-target` attribute to the first focusable descendant 148 | starting from the firstChild necessary for the focus to be delegated 149 | within the flow-component-renderer when used inside a vaadin-grid cell */ 150 | _defineFocusTarget() { 151 | var focusable = this._getFirstFocusableDescendant(this.firstChild); 152 | if (focusable !== null) { 153 | focusable.setAttribute('focus-target', 'true'); 154 | } 155 | } 156 | 157 | _getFirstFocusableDescendant(node) { 158 | if (this._isFocusable(node)) { 159 | return node; 160 | } 161 | if (node.hasAttribute && (node.hasAttribute('disabled') || node.hasAttribute('hidden'))) { 162 | return null; 163 | } 164 | if (!node.children) { 165 | return null; 166 | } 167 | for (var i = 0; i < node.children.length; i++) { 168 | var focusable = this._getFirstFocusableDescendant(node.children[i]); 169 | if (focusable !== null) { 170 | return focusable; 171 | } 172 | } 173 | return null; 174 | } 175 | 176 | _isFocusable(node) { 177 | if ( 178 | node.hasAttribute && 179 | typeof node.hasAttribute === 'function' && 180 | (node.hasAttribute('disabled') || node.hasAttribute('hidden')) 181 | ) { 182 | return false; 183 | } 184 | 185 | return node.tabIndex === 0; 186 | } 187 | 188 | _onAnimationEnd(e) { 189 | // ShadyCSS applies scoping suffixes to animation names 190 | // To ensure that child is attached once element is unhidden 191 | // for when it was filtered out from, eg, ComboBox 192 | // https://github.com/vaadin/vaadin-flow-components/issues/437 193 | if (e.animationName.indexOf('flow-component-renderer-appear') === 0) { 194 | this._attachRenderedComponentIfAble(); 195 | } 196 | } 197 | } 198 | window.customElements.define(FlowComponentRenderer.is, FlowComponentRenderer); 199 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './Flow'; 2 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/index.js: -------------------------------------------------------------------------------- 1 | export * from './Flow'; 2 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/main/frontend/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC","sourcesContent":["export * from './Flow';\n"]} -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/lit-renderer.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-restricted-syntax */ 2 | /* eslint-disable max-params */ 3 | import { html, render } from 'lit'; 4 | import { live } from 'lit/directives/live.js'; 5 | 6 | type RenderRoot = HTMLElement & { __litRenderer?: Renderer; _$litPart$?: any }; 7 | 8 | type ItemModel = { item: any; index: number }; 9 | 10 | type Renderer = ((root: RenderRoot, rendererOwner: HTMLElement, model: ItemModel) => void) & { __rendererId?: string }; 11 | 12 | type Component = HTMLElement & { [key: string]: Renderer | undefined }; 13 | 14 | const _window = window as any; 15 | _window.Vaadin = _window.Vaadin || {}; 16 | 17 | /** 18 | * Assigns the component a renderer function which uses Lit to render 19 | * the given template expression inside the render root element. 20 | * 21 | * @param component The host component to which the renderer runction is to be set 22 | * @param rendererName The name of the renderer function 23 | * @param templateExpression The content of the template literal passed to Lit for rendering. 24 | * @param returnChannel A channel to the server. 25 | * Calling it will end up invoking a handler in the server-side LitRenderer. 26 | * @param clientCallables A list of function names that can be called from within the template literal. 27 | * @param propertyNamespace LitRenderer-specific namespace for properties. 28 | * Needed to avoid property name collisions between renderers. 29 | */ 30 | _window.Vaadin.setLitRenderer = ( 31 | component: Component, 32 | rendererName: string, 33 | templateExpression: string, 34 | returnChannel: (name: string, itemKey: string, args: any[]) => void, 35 | clientCallables: string[], 36 | propertyNamespace: string, 37 | appId: string 38 | ) => { 39 | const callablesCreator = (itemKey: string) => { 40 | return clientCallables.map((clientCallable) => (...args: any[]) => { 41 | if (itemKey !== undefined) { 42 | returnChannel(clientCallable, itemKey, args[0] instanceof Event ? [] : [...args]); 43 | } 44 | }); 45 | }; 46 | const fnArgs = [ 47 | 'html', 48 | 'root', 49 | 'live', 50 | 'appId', 51 | 'itemKey', 52 | 'model', 53 | 'item', 54 | 'index', 55 | ...clientCallables, 56 | `return html\`${templateExpression}\`` 57 | ]; 58 | const htmlGenerator = new Function(...fnArgs); 59 | const renderFunction = (root: RenderRoot, model: ItemModel, itemKey: string) => { 60 | const { item, index } = model; 61 | render(htmlGenerator(html, root, live, appId, itemKey, model, item, index, ...callablesCreator(itemKey)), root); 62 | }; 63 | 64 | const renderer: Renderer = (root, _, model) => { 65 | const { item } = model; 66 | // Clean up the root element of any existing content 67 | // (and Lit's _$litPart$ property) from other renderers 68 | // TODO: Remove once https://github.com/vaadin/web-components/issues/2235 is done 69 | if (root.__litRenderer !== renderer) { 70 | root.innerHTML = ''; 71 | delete root._$litPart$; 72 | root.__litRenderer = renderer; 73 | } 74 | 75 | // Map a new item that only includes the properties defined by 76 | // this specific LitRenderer instance. The renderer instance specific 77 | // "propertyNamespace" prefix is stripped from the property name at this point: 78 | // 79 | // item: { key: "2", lr_3769df5394a74ef3_lastName: "Tyler"} 80 | // -> 81 | // mappedItem: { lastName: "Tyler" } 82 | const mappedItem: { [key: string]: any } = {}; 83 | for (const key in item) { 84 | if (key.startsWith(propertyNamespace)) { 85 | mappedItem[key.replace(propertyNamespace, '')] = item[key]; 86 | } 87 | } 88 | 89 | renderFunction(root, { ...model, item: mappedItem }, item.key); 90 | }; 91 | 92 | renderer.__rendererId = propertyNamespace; 93 | component[rendererName] = renderer; 94 | }; 95 | 96 | /** 97 | * Removes the renderer function with the given name from the component 98 | * if the propertyNamespace matches the renderer's id. 99 | * 100 | * @param component The host component whose renderer function is to be removed 101 | * @param rendererName The name of the renderer function 102 | * @param rendererId The rendererId of the function to be removed 103 | */ 104 | _window.Vaadin.unsetLitRenderer = (component: Component, rendererName: string, rendererId: string) => { 105 | // The check for __rendererId property is necessary since the renderer function 106 | // may get overridden by another renderer, for example, by one coming from 107 | // vaadin-template-renderer. We don't want LitRenderer registration cleanup to 108 | // unintentionally remove the new renderer. 109 | if (component[rendererName]?.__rendererId === rendererId) { 110 | component[rendererName] = undefined; 111 | } 112 | }; 113 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/menubarConnector.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2000-2024 Vaadin Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | import './contextMenuConnector.js'; 17 | 18 | /** 19 | * Initializes the connector for a menu bar element. 20 | * 21 | * @param {HTMLElement} menubar 22 | * @param {string} appId 23 | */ 24 | function initLazy(menubar, appId) { 25 | if (menubar.$connector) { 26 | return; 27 | } 28 | 29 | const observer = new MutationObserver((records) => { 30 | const hasChangedAttributes = records.some((entry) => { 31 | const oldValue = entry.oldValue; 32 | const newValue = entry.target.getAttribute(entry.attributeName); 33 | return oldValue !== newValue; 34 | }); 35 | 36 | if (hasChangedAttributes) { 37 | menubar.$connector.generateItems(); 38 | } 39 | }); 40 | 41 | menubar.$connector = { 42 | /** 43 | * Generates and assigns the items to the menu bar. 44 | * 45 | * When the method is called without providing a node id, 46 | * the previously generated items tree will be used. 47 | * That can be useful if you only want to sync the disabled and hidden properties of root items. 48 | * 49 | * @param {number | undefined} nodeId 50 | */ 51 | generateItems(nodeId) { 52 | if (!menubar.shadowRoot) { 53 | // workaround for https://github.com/vaadin/flow/issues/5722 54 | setTimeout(() => menubar.$connector.generateItems(nodeId)); 55 | return; 56 | } 57 | 58 | if (!menubar._container) { 59 | // Menu-bar defers first buttons render to avoid re-layout 60 | // See https://github.com/vaadin/web-components/issues/7271 61 | queueMicrotask(() => menubar.$connector.generateItems(nodeId)); 62 | return; 63 | } 64 | 65 | if (nodeId) { 66 | menubar.__generatedItems = window.Vaadin.Flow.contextMenuConnector.generateItemsTree(appId, nodeId); 67 | } 68 | 69 | let items = menubar.__generatedItems || []; 70 | 71 | items.forEach((item) => { 72 | // Propagate disabled state from items to parent buttons 73 | item.disabled = item.component.disabled; 74 | 75 | // Saving item to component because `_item` can be reassigned to a new value 76 | // when the component goes to the overflow menu 77 | item.component._rootItem = item; 78 | }); 79 | 80 | // Observe for hidden and disabled attributes in case they are changed by Flow. 81 | // When a change occurs, the observer will re-generate items on top of the existing tree 82 | // to sync the new attribute values with the corresponding properties in the items array. 83 | items.forEach((item) => { 84 | observer.observe(item.component, { 85 | attributeFilter: ['hidden', 'disabled'], 86 | attributeOldValue: true 87 | }); 88 | }); 89 | 90 | // Remove hidden items entirely from the array. Just hiding them 91 | // could cause the overflow button to be rendered without items. 92 | // 93 | // The items-prop needs to be set even when all items are visible 94 | // to update the disabled state and re-render buttons. 95 | items = items.filter((item) => !item.component.hidden); 96 | 97 | menubar.items = items; 98 | 99 | // Propagate click events from the menu buttons to the item components 100 | menubar._buttons.forEach((button) => { 101 | if (button.item && button.item.component) { 102 | button.addEventListener('click', (e) => { 103 | if (e.composedPath().indexOf(button.item.component) === -1) { 104 | button.item.component.click(); 105 | e.stopPropagation(); 106 | } 107 | }); 108 | } 109 | }); 110 | } 111 | }; 112 | } 113 | 114 | function setClassName(component) { 115 | const item = component._rootItem || component._item; 116 | 117 | if (item) { 118 | item.className = component.className; 119 | } 120 | } 121 | 122 | window.Vaadin.Flow.menubarConnector = { initLazy, setClassName }; 123 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/messageListConnector.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2000-2024 Vaadin Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | window.Vaadin.Flow.messageListConnector = { 17 | setItems(list, items, locale) { 18 | const formatter = new Intl.DateTimeFormat(locale, { 19 | year: 'numeric', 20 | month: 'short', 21 | day: 'numeric', 22 | hour: 'numeric', 23 | minute: 'numeric' 24 | }); 25 | list.items = items.map((item) => 26 | item.time 27 | ? Object.assign(item, { 28 | time: formatter.format(new Date(item.time)) 29 | }) 30 | : item 31 | ); 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/selectConnector.js: -------------------------------------------------------------------------------- 1 | window.Vaadin.Flow.selectConnector = {}; 2 | window.Vaadin.Flow.selectConnector.initLazy = (select) => { 3 | // do not init this connector twice for the given select 4 | if (select.$connector) { 5 | return; 6 | } 7 | 8 | select.$connector = {}; 9 | 10 | select.renderer = (root) => { 11 | const listBox = select.querySelector('vaadin-select-list-box'); 12 | if (listBox) { 13 | if (root.firstChild) { 14 | root.removeChild(root.firstChild); 15 | } 16 | root.appendChild(listBox); 17 | } 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/theme-util.js: -------------------------------------------------------------------------------- 1 | import stripCssComments from 'strip-css-comments'; 2 | 3 | // Safari 15 - 16.3, polyfilled 4 | const polyfilledSafari = CSSStyleSheet.toString().includes('document.createElement'); 5 | 6 | const createLinkReferences = (css, target) => { 7 | // Unresolved urls are written as '@import url(text);' or '@import "text";' to the css 8 | // media query can be present on @media tag or on @import directive after url 9 | // Note that with Vite production build there is no space between @import and "text" 10 | // [0] is the full match 11 | // [1] matches the media query 12 | // [2] matches the url 13 | // [3] matches the quote char surrounding in '@import "..."' 14 | // [4] matches the url in '@import "..."' 15 | // [5] matches media query on @import statement 16 | const importMatcher = 17 | /(?:@media\s(.+?))?(?:\s{)?\@import\s*(?:url\(\s*['"]?(.+?)['"]?\s*\)|(["'])((?:\\.|[^\\])*?)\3)([^;]*);(?:})?/g; 18 | 19 | // Only cleanup if comment exist 20 | if (/\/\*(.|[\r\n])*?\*\//gm.exec(css) != null) { 21 | // clean up comments 22 | css = stripCssComments(css); 23 | } 24 | 25 | var match; 26 | var styleCss = css; 27 | 28 | // For each external url import add a link reference 29 | while ((match = importMatcher.exec(css)) !== null) { 30 | styleCss = styleCss.replace(match[0], ''); 31 | const link = document.createElement('link'); 32 | link.rel = 'stylesheet'; 33 | link.href = match[2] || match[4]; 34 | const media = match[1] || match[5]; 35 | if (media) { 36 | link.media = media; 37 | } 38 | // For target document append to head else append to target 39 | if (target === document) { 40 | document.head.appendChild(link); 41 | } else { 42 | target.appendChild(link); 43 | } 44 | } 45 | return styleCss; 46 | }; 47 | 48 | const addAdoptedStyleSafariPolyfill = (sheet, target, first) => { 49 | if (first) { 50 | target.adoptedStyleSheets = [sheet, ...target.adoptedStyleSheets]; 51 | } else { 52 | target.adoptedStyleSheets = [...target.adoptedStyleSheets, sheet]; 53 | } 54 | return () => { 55 | target.adoptedStyleSheets = target.adoptedStyleSheets.filter((ss) => ss !== sheet); 56 | }; 57 | }; 58 | 59 | const addAdoptedStyle = (cssText, target, first) => { 60 | const sheet = new CSSStyleSheet(); 61 | sheet.replaceSync(cssText); 62 | if (polyfilledSafari) { 63 | return addAdoptedStyleSafariPolyfill(sheet, target, first); 64 | } 65 | if (first) { 66 | target.adoptedStyleSheets.splice(0, 0, sheet); 67 | } else { 68 | target.adoptedStyleSheets.push(sheet); 69 | } 70 | return () => { 71 | target.adoptedStyleSheets.splice(target.adoptedStyleSheets.indexOf(sheet), 1); 72 | }; 73 | }; 74 | 75 | const addStyleTag = (cssText, referenceComment) => { 76 | const styleTag = document.createElement('style'); 77 | styleTag.type = 'text/css'; 78 | styleTag.textContent = cssText; 79 | 80 | let beforeThis = undefined; 81 | if (referenceComment) { 82 | const comments = Array.from(document.head.childNodes).filter(elem => elem.nodeType === Node.COMMENT_NODE); 83 | const container = comments.find(comment => comment.data.trim() === referenceComment); 84 | if (container) { 85 | beforeThis = container; 86 | } 87 | } 88 | document.head.insertBefore(styleTag, beforeThis); 89 | return () => { 90 | styleTag.remove(); 91 | }; 92 | }; 93 | 94 | // target: Document | ShadowRoot 95 | export const injectGlobalCss = (css, referenceComment, target, first) => { 96 | if (target === document) { 97 | const hash = getHash(css); 98 | if (window.Vaadin.theme.injectedGlobalCss.indexOf(hash) !== -1) { 99 | return; 100 | } 101 | window.Vaadin.theme.injectedGlobalCss.push(hash); 102 | } 103 | const cssText = createLinkReferences(css, target); 104 | 105 | // We avoid mixing style tags and adoptedStyleSheets to make override order clear 106 | if (target === document) { 107 | return addStyleTag(cssText, referenceComment); 108 | } 109 | 110 | return addAdoptedStyle(cssText, target, first); 111 | }; 112 | 113 | window.Vaadin = window.Vaadin || {}; 114 | window.Vaadin.theme = window.Vaadin.theme || {}; 115 | window.Vaadin.theme.injectedGlobalCss = []; 116 | 117 | const webcomponentGlobalCss = { 118 | css: [], 119 | importers: [] 120 | }; 121 | 122 | export const injectGlobalWebcomponentCss = (css) => { 123 | webcomponentGlobalCss.css.push(css); 124 | webcomponentGlobalCss.importers.forEach(registrar => { 125 | registrar(css); 126 | }); 127 | }; 128 | 129 | export const webcomponentGlobalCssInjector = (registrar) => { 130 | const registeredCss = []; 131 | const wrapper = (css) => { 132 | const hash = getHash(css); 133 | if (!registeredCss.includes(hash)) { 134 | registeredCss.push(hash); 135 | registrar(css); 136 | } 137 | }; 138 | webcomponentGlobalCss.importers.push(wrapper); 139 | webcomponentGlobalCss.css.forEach(wrapper); 140 | }; 141 | 142 | /** 143 | * Calculate a 32 bit FNV-1a hash 144 | * Found here: https://gist.github.com/vaiorabbit/5657561 145 | * Ref.: http://isthe.com/chongo/tech/comp/fnv/ 146 | * 147 | * @param {string} str the input value 148 | * @returns {string} 32 bit (as 8 byte hex string) 149 | */ 150 | function hashFnv32a(str) { 151 | /*jshint bitwise:false */ 152 | let i, 153 | l, 154 | hval = 0x811c9dc5; 155 | 156 | for (i = 0, l = str.length; i < l; i++) { 157 | hval ^= str.charCodeAt(i); 158 | hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24); 159 | } 160 | 161 | // Convert to 8 digit hex string 162 | return ('0000000' + (hval >>> 0).toString(16)).substr(-8); 163 | } 164 | 165 | /** 166 | * Calculate a 64 bit hash for the given input. 167 | * Double hash is used to significantly lower the collision probability. 168 | * 169 | * @param {string} input value to get hash for 170 | * @returns {string} 64 bit (as 16 byte hex string) 171 | */ 172 | function getHash(input) { 173 | let h1 = hashFnv32a(input); // returns 32 bit (as 8 byte hex string) 174 | return h1 + hashFnv32a(h1 + input); 175 | } 176 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/tooltip.ts: -------------------------------------------------------------------------------- 1 | import { Tooltip } from '@vaadin/tooltip/src/vaadin-tooltip.js'; 2 | 3 | const _window = window as any; 4 | _window.Vaadin ||= {}; 5 | _window.Vaadin.Flow ||= {}; 6 | _window.Vaadin.Flow.tooltip ||= {}; 7 | 8 | Object.assign(_window.Vaadin.Flow.tooltip, { 9 | setDefaultHideDelay: (hideDelay: number) => Tooltip.setDefaultHideDelay(hideDelay), 10 | setDefaultFocusDelay: (focusDelay: number) => Tooltip.setDefaultFocusDelay(focusDelay), 11 | setDefaultHoverDelay: (hoverDelay: number) => Tooltip.setDefaultHoverDelay(hoverDelay) 12 | }); 13 | 14 | const { defaultHideDelay, defaultFocusDelay, defaultHoverDelay } = _window.Vaadin.Flow.tooltip; 15 | if (defaultHideDelay) { 16 | Tooltip.setDefaultHideDelay(defaultHideDelay); 17 | } 18 | if (defaultFocusDelay) { 19 | Tooltip.setDefaultFocusDelay(defaultFocusDelay); 20 | } 21 | if (defaultHoverDelay) { 22 | Tooltip.setDefaultHoverDelay(defaultHoverDelay); 23 | } 24 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/vaadin-big-decimal-field.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2000-2024 Vaadin Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | let memoizedTemplate; 17 | 18 | customElements.whenDefined('vaadin-text-field').then(() => { 19 | class BigDecimalFieldElement extends customElements.get('vaadin-text-field') { 20 | static get template() { 21 | if (!memoizedTemplate) { 22 | memoizedTemplate = super.template.cloneNode(true); 23 | memoizedTemplate.innerHTML += ``; 36 | } 37 | return memoizedTemplate; 38 | } 39 | 40 | static get is() { 41 | return 'vaadin-big-decimal-field'; 42 | } 43 | 44 | static get properties() { 45 | return { 46 | _decimalSeparator: { 47 | type: String, 48 | value: '.', 49 | observer: '__decimalSeparatorChanged' 50 | } 51 | }; 52 | } 53 | 54 | ready() { 55 | super.ready(); 56 | this.inputElement.setAttribute('inputmode', 'decimal'); 57 | } 58 | 59 | __decimalSeparatorChanged(separator, oldSeparator) { 60 | this.allowedCharPattern = '[-+\\d' + separator + ']'; 61 | 62 | if (this.value && oldSeparator) { 63 | this.value = this.value.split(oldSeparator).join(separator); 64 | } 65 | } 66 | } 67 | 68 | customElements.define(BigDecimalFieldElement.is, BigDecimalFieldElement); 69 | }); 70 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/vaadin-dev-tools/License.d.ts: -------------------------------------------------------------------------------- 1 | import { ServerMessage } from "./vaadin-dev-tools"; 2 | export interface Product { 3 | name: string; 4 | version: string; 5 | } 6 | export interface ProductAndMessage { 7 | message: string; 8 | messageHtml?: string; 9 | product: Product; 10 | } 11 | export declare const findAll: (element: Element | ShadowRoot | Document, tags: string[]) => Element[]; 12 | export declare const licenseCheckOk: (data: Product) => void; 13 | export declare const licenseCheckFailed: (data: ProductAndMessage) => void; 14 | export declare const licenseCheckNoKey: (data: ProductAndMessage) => void; 15 | export declare const handleLicenseMessage: (message: ServerMessage) => boolean; 16 | export declare const licenseInit: () => void; 17 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/vaadin-dev-tools/connection.d.ts: -------------------------------------------------------------------------------- 1 | export declare enum ConnectionStatus { 2 | ACTIVE = "active", 3 | INACTIVE = "inactive", 4 | UNAVAILABLE = "unavailable", 5 | ERROR = "error" 6 | } 7 | export declare abstract class Connection { 8 | static HEARTBEAT_INTERVAL: number; 9 | status: ConnectionStatus; 10 | onHandshake(): void; 11 | onConnectionError(_: string): void; 12 | onStatusChange(_: ConnectionStatus): void; 13 | setActive(yes: boolean): void; 14 | setStatus(status: ConnectionStatus): void; 15 | } 16 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/vaadin-dev-tools/live-reload-connection.d.ts: -------------------------------------------------------------------------------- 1 | import { Connection } from './connection.js'; 2 | export declare class LiveReloadConnection extends Connection { 3 | webSocket?: WebSocket; 4 | constructor(url: string); 5 | onReload(_strategy: string): void; 6 | handleMessage(msg: any): void; 7 | handleError(msg: any): void; 8 | } 9 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/vaadin-dev-tools/vaadin-dev-tools.d.ts: -------------------------------------------------------------------------------- 1 | import { LitElement } from 'lit'; 2 | import { Product } from './License'; 3 | import { ConnectionStatus } from './connection'; 4 | /** 5 | * Plugin API for the dev tools window. 6 | */ 7 | export interface DevToolsInterface { 8 | send(command: string, data: any): void; 9 | } 10 | export interface MessageHandler { 11 | handleMessage(message: ServerMessage): boolean; 12 | } 13 | export interface ServerMessage { 14 | /** 15 | * The command 16 | */ 17 | command: string; 18 | /** 19 | * the data for the command 20 | */ 21 | data: any; 22 | } 23 | /** 24 | * To create and register a plugin, use e.g. 25 | * @example 26 | * export class MyTab extends LitElement implements MessageHandler { 27 | * render() { 28 | * return html`
Here I am
`; 29 | * } 30 | * } 31 | * customElements.define('my-tab', MyTab); 32 | * 33 | * const plugin: DevToolsPlugin = { 34 | * init: function (devToolsInterface: DevToolsInterface): void { 35 | * devToolsInterface.addTab('Tab title', 'my-tab') 36 | * } 37 | * }; 38 | * 39 | * (window as any).Vaadin.devToolsPlugins.push(plugin); 40 | */ 41 | export interface DevToolsPlugin { 42 | /** 43 | * Called once to initialize the plugin. 44 | * 45 | * @param devToolsInterface provides methods to interact with the dev tools 46 | */ 47 | init(devToolsInterface: DevToolsInterface): void; 48 | } 49 | export declare enum MessageType { 50 | LOG = "log", 51 | INFORMATION = "information", 52 | WARNING = "warning", 53 | ERROR = "error" 54 | } 55 | type DevToolsConf = { 56 | enable: boolean; 57 | url: string; 58 | backend?: string; 59 | liveReloadPort: number; 60 | token?: string; 61 | }; 62 | export declare class VaadinDevTools extends LitElement { 63 | unhandledMessages: ServerMessage[]; 64 | conf: DevToolsConf; 65 | static get styles(): import("lit").CSSResult[]; 66 | static DISMISSED_NOTIFICATIONS_IN_LOCAL_STORAGE: string; 67 | static ACTIVE_KEY_IN_SESSION_STORAGE: string; 68 | static TRIGGERED_KEY_IN_SESSION_STORAGE: string; 69 | static TRIGGERED_COUNT_KEY_IN_SESSION_STORAGE: string; 70 | static AUTO_DEMOTE_NOTIFICATION_DELAY: number; 71 | static HOTSWAP_AGENT: string; 72 | static JREBEL: string; 73 | static SPRING_BOOT_DEVTOOLS: string; 74 | static BACKEND_DISPLAY_NAME: Record; 75 | static get isActive(): boolean; 76 | frontendStatus: ConnectionStatus; 77 | javaStatus: ConnectionStatus; 78 | private root; 79 | componentPickActive: boolean; 80 | private javaConnection?; 81 | private frontendConnection?; 82 | private nextMessageId; 83 | private transitionDuration; 84 | elementTelemetry(): void; 85 | openWebSocketConnection(): void; 86 | tabHandleMessage(tabElement: HTMLElement, message: ServerMessage): boolean; 87 | handleFrontendMessage(message: ServerMessage): void; 88 | handleHmrMessage(message: ServerMessage): boolean; 89 | getDedicatedWebSocketUrl(): string | undefined; 90 | getSpringBootWebSocketUrl(location: any): string; 91 | connectedCallback(): void; 92 | initPlugin(plugin: DevToolsPlugin): Promise; 93 | format(o: any): string; 94 | checkLicense(productInfo: Product): void; 95 | setActive(yes: boolean): void; 96 | render(): import("lit-html").TemplateResult<1>; 97 | setJavaLiveReloadActive(active: boolean): void; 98 | } 99 | export {}; 100 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/vaadin-dev-tools/websocket-connection.d.ts: -------------------------------------------------------------------------------- 1 | import { Connection } from './connection'; 2 | export declare class WebSocketConnection extends Connection { 3 | static HEARTBEAT_INTERVAL: number; 4 | socket?: any; 5 | canSend: boolean; 6 | constructor(url: string); 7 | onReload(_strategy: string): void; 8 | onUpdate(_path: string, _content: string): void; 9 | onMessage(_message: any): void; 10 | handleMessage(msg: any): void; 11 | handleError(msg: any): void; 12 | send(command: string, data: any): void; 13 | } 14 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/vaadin-grid-flow-selection-column.js: -------------------------------------------------------------------------------- 1 | import '@vaadin/grid/vaadin-grid-column.js'; 2 | import { GridColumn } from '@vaadin/grid/src/vaadin-grid-column.js'; 3 | import { GridSelectionColumnBaseMixin } from '@vaadin/grid/src/vaadin-grid-selection-column-base-mixin.js'; 4 | 5 | export class GridFlowSelectionColumn extends GridSelectionColumnBaseMixin(GridColumn) { 6 | static get is() { 7 | return 'vaadin-grid-flow-selection-column'; 8 | } 9 | 10 | static get properties() { 11 | return { 12 | /** 13 | * Override property to enable auto-width 14 | */ 15 | autoWidth: { 16 | type: Boolean, 17 | value: true 18 | }, 19 | 20 | /** 21 | * Override property to set custom width 22 | */ 23 | width: { 24 | type: String, 25 | value: '56px' 26 | } 27 | }; 28 | } 29 | 30 | /** 31 | * Override method from `GridSelectionColumnBaseMixin` to add ID to select all 32 | * checkbox 33 | * 34 | * @override 35 | */ 36 | _defaultHeaderRenderer(root, _column) { 37 | super._defaultHeaderRenderer(root, _column); 38 | const checkbox = root.firstElementChild; 39 | if (checkbox) { 40 | checkbox.id = 'selectAllCheckbox'; 41 | } 42 | } 43 | 44 | /** 45 | * Override a method from `GridSelectionColumnBaseMixin` to handle the user 46 | * selecting all items. 47 | * 48 | * @protected 49 | * @override 50 | */ 51 | _selectAll() { 52 | this.selectAll = true; 53 | this.$server.selectAll(); 54 | } 55 | 56 | /** 57 | * Override a method from `GridSelectionColumnBaseMixin` to handle the user 58 | * deselecting all items. 59 | * 60 | * @protected 61 | * @override 62 | */ 63 | _deselectAll() { 64 | this.selectAll = false; 65 | this.$server.deselectAll(); 66 | } 67 | 68 | /** 69 | * Override a method from `GridSelectionColumnBaseMixin` to handle the user 70 | * selecting an item. 71 | * 72 | * @param {Object} item the item to select 73 | * @protected 74 | * @override 75 | */ 76 | _selectItem(item) { 77 | this._grid.$connector.doSelection([item], true); 78 | } 79 | 80 | /** 81 | * Override a method from `GridSelectionColumnBaseMixin` to handle the user 82 | * deselecting an item. 83 | * 84 | * @param {Object} item the item to deselect 85 | * @protected 86 | * @override 87 | */ 88 | _deselectItem(item) { 89 | this._grid.$connector.doDeselection([item], true); 90 | // Optimistically update select all state 91 | this.selectAll = false; 92 | } 93 | } 94 | 95 | customElements.define(GridFlowSelectionColumn.is, GridFlowSelectionColumn); 96 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/vaadin-popover/popover.ts: -------------------------------------------------------------------------------- 1 | import { Popover } from '@vaadin/popover/src/vaadin-popover.js'; 2 | 3 | const _window = window as any; 4 | _window.Vaadin ||= {}; 5 | _window.Vaadin.Flow ||= {}; 6 | _window.Vaadin.Flow.popover ||= {}; 7 | 8 | Object.assign(_window.Vaadin.Flow.popover, { 9 | setDefaultHideDelay: (hideDelay: number) => Popover.setDefaultHideDelay(hideDelay), 10 | setDefaultFocusDelay: (focusDelay: number) => Popover.setDefaultFocusDelay(focusDelay), 11 | setDefaultHoverDelay: (hoverDelay: number) => Popover.setDefaultHoverDelay(hoverDelay) 12 | }); 13 | 14 | const { defaultHideDelay, defaultFocusDelay, defaultHoverDelay } = _window.Vaadin.Flow.popover; 15 | 16 | if (defaultHideDelay) { 17 | Popover.setDefaultHideDelay(defaultHideDelay); 18 | } 19 | 20 | if (defaultFocusDelay) { 21 | Popover.setDefaultFocusDelay(defaultFocusDelay); 22 | } 23 | 24 | if (defaultHoverDelay) { 25 | Popover.setDefaultHoverDelay(defaultHoverDelay); 26 | } 27 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/vaadin-time-picker/helpers.js: -------------------------------------------------------------------------------- 1 | // map from unicode eastern arabic number characters to arabic numbers 2 | const EASTERN_ARABIC_DIGIT_MAP = { 3 | '\\u0660': '0', 4 | '\\u0661': '1', 5 | '\\u0662': '2', 6 | '\\u0663': '3', 7 | '\\u0664': '4', 8 | '\\u0665': '5', 9 | '\\u0666': '6', 10 | '\\u0667': '7', 11 | '\\u0668': '8', 12 | '\\u0669': '9' 13 | }; 14 | 15 | /** 16 | * Escapes the given string so it can be safely used in a regexp. 17 | * 18 | * @param {string} string 19 | * @return {string} 20 | */ 21 | function escapeRegExp(string) { 22 | return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); 23 | } 24 | 25 | /** 26 | * Parses eastern arabic number characters to arabic numbers (0-9) 27 | * 28 | * @param {string} digits 29 | * @return {string} 30 | */ 31 | function parseEasternArabicDigits(digits) { 32 | return digits.replace(/[\u0660-\u0669]/g, function (char) { 33 | const unicode = '\\u0' + char.charCodeAt(0).toString(16); 34 | return EASTERN_ARABIC_DIGIT_MAP[unicode]; 35 | }); 36 | } 37 | 38 | /** 39 | * @param {string} locale 40 | * @param {Date} testTime 41 | * @return {string | null} 42 | */ 43 | function getAmOrPmString(locale, testTime) { 44 | const testTimeString = testTime.toLocaleTimeString(locale); 45 | 46 | // AM/PM string is anything from one letter in eastern arabic to standard two letters, 47 | // to having space in between, dots ... 48 | // cannot disqualify whitespace since some locales use a. m. / p. m. 49 | // TODO when more scripts support is added (than Arabic), need to exclude those numbers too 50 | const amOrPmRegExp = /[^\d\u0660-\u0669]/; 51 | 52 | const matches = 53 | // In most locales, the time ends with AM/PM: 54 | testTimeString.match(new RegExp(`${amOrPmRegExp.source}+$`, 'g')) || 55 | // In some locales, the time starts with AM/PM e.g in Chinese: 56 | testTimeString.match(new RegExp(`^${amOrPmRegExp.source}+`, 'g')); 57 | 58 | return matches && matches[0].trim(); 59 | } 60 | 61 | /** 62 | * @param {string} locale 63 | * @return {string | null} 64 | */ 65 | export function getSeparator(locale) { 66 | let timeString = TEST_PM_TIME.toLocaleTimeString(locale); 67 | 68 | // Since the next regex picks first non-number-whitespace, 69 | // need to discard possible PM from beginning (eg. chinese locale) 70 | const pmString = getPmString(locale); 71 | if (pmString && timeString.startsWith(pmString)) { 72 | timeString = timeString.replace(pmString, ''); 73 | } 74 | 75 | const matches = timeString.match(/[^\u0660-\u0669\s\d]/); 76 | return matches && matches[0]; 77 | } 78 | 79 | /** 80 | * Searches for either an AM or PM token in the given time string 81 | * depending on what is provided in `amOrPmString`. 82 | * 83 | * The search is case and space insensitive. 84 | * 85 | * @example 86 | * `searchAmOrPmToken('1 P M', 'PM')` => `'P M'` 87 | * 88 | * @example 89 | * `searchAmOrPmToken('1 a.m.', 'A. M.')` => `a.m.` 90 | * 91 | * @param {string} timeString 92 | * @param {string} amOrPmString 93 | * @return {string | null} 94 | */ 95 | export function searchAmOrPmToken(timeString, amOrPmString) { 96 | if (!amOrPmString) return null; 97 | 98 | // Create a regexp string for searching for AM/PM without space-sensitivity. 99 | const tokenRegExpString = amOrPmString.split(/\s*/).map(escapeRegExp).join('\\s*'); 100 | 101 | // Create a regexp without case-sensitivity. 102 | const tokenRegExp = new RegExp(tokenRegExpString, 'i'); 103 | 104 | // Match the regexp against the time string. 105 | const tokenMatches = timeString.match(tokenRegExp); 106 | if (tokenMatches) { 107 | return tokenMatches[0]; 108 | } 109 | } 110 | 111 | export const TEST_PM_TIME = new Date('August 19, 1975 23:15:30'); 112 | 113 | export const TEST_AM_TIME = new Date('August 19, 1975 05:15:30'); 114 | 115 | /** 116 | * @param {string} locale 117 | * @return {string} 118 | */ 119 | export function getPmString(locale) { 120 | return getAmOrPmString(locale, TEST_PM_TIME); 121 | } 122 | 123 | /** 124 | * @param {string} locale 125 | * @return {string} 126 | */ 127 | export function getAmString(locale) { 128 | return getAmOrPmString(locale, TEST_AM_TIME); 129 | } 130 | 131 | /** 132 | * @param {string} digits 133 | * @return {number} 134 | */ 135 | export function parseDigitsIntoInteger(digits) { 136 | return parseInt(parseEasternArabicDigits(digits)); 137 | } 138 | 139 | /** 140 | * @param {string} milliseconds 141 | * @return {number} 142 | */ 143 | export function parseMillisecondsIntoInteger(milliseconds) { 144 | milliseconds = parseEasternArabicDigits(milliseconds); 145 | // digits are either .1 .01 or .001 so need to "shift" 146 | if (milliseconds.length === 1) { 147 | milliseconds += '00'; 148 | } else if (milliseconds.length === 2) { 149 | milliseconds += '0'; 150 | } 151 | return parseInt(milliseconds); 152 | } 153 | 154 | /** 155 | * @param {string} timeString 156 | * @param {number} milliseconds 157 | * @param {string} amString 158 | * @param {string} pmString 159 | * @return {string} 160 | */ 161 | export function formatMilliseconds(timeString, milliseconds, amString, pmString) { 162 | // might need to inject milliseconds between seconds and AM/PM 163 | let cleanedTimeString = timeString; 164 | if (timeString.endsWith(amString)) { 165 | cleanedTimeString = timeString.replace(' ' + amString, ''); 166 | } else if (timeString.endsWith(pmString)) { 167 | cleanedTimeString = timeString.replace(' ' + pmString, ''); 168 | } 169 | if (milliseconds) { 170 | let millisecondsString = milliseconds < 10 ? '0' : ''; 171 | millisecondsString += milliseconds < 100 ? '0' : ''; 172 | millisecondsString += milliseconds; 173 | cleanedTimeString += '.' + millisecondsString; 174 | } else { 175 | cleanedTimeString += '.000'; 176 | } 177 | if (timeString.endsWith(amString)) { 178 | cleanedTimeString = cleanedTimeString + ' ' + amString; 179 | } else if (timeString.endsWith(pmString)) { 180 | cleanedTimeString = cleanedTimeString + ' ' + pmString; 181 | } 182 | return cleanedTimeString; 183 | } 184 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/vaadin-time-picker/timepickerConnector.js: -------------------------------------------------------------------------------- 1 | import { 2 | TEST_PM_TIME, 3 | formatMilliseconds, 4 | parseMillisecondsIntoInteger, 5 | parseDigitsIntoInteger, 6 | getAmString, 7 | getPmString, 8 | getSeparator, 9 | searchAmOrPmToken 10 | } from './helpers.js'; 11 | import { parseISOTime } from '@vaadin/time-picker/src/vaadin-time-picker-helper.js'; 12 | 13 | // Execute callback when predicate returns true. 14 | // Try again later if predicate returns false. 15 | function when(predicate, callback, timeout = 0) { 16 | if (predicate()) { 17 | callback(); 18 | } else { 19 | setTimeout(() => when(predicate, callback, 200), timeout); 20 | } 21 | } 22 | 23 | function parseISO(text) { 24 | // The default i18n parser of the web component is ISO 8601 compliant. 25 | const timeObject = parseISOTime(text); 26 | 27 | // The web component returns an object with string values 28 | // while the connector expects number values. 29 | return { 30 | hours: parseInt(timeObject.hours || 0), 31 | minutes: parseInt(timeObject.minutes || 0), 32 | seconds: parseInt(timeObject.seconds || 0), 33 | milliseconds: parseInt(timeObject.milliseconds || 0) 34 | }; 35 | } 36 | 37 | window.Vaadin.Flow.timepickerConnector = {}; 38 | window.Vaadin.Flow.timepickerConnector.initLazy = (timepicker) => { 39 | // Check whether the connector was already initialized for the timepicker 40 | if (timepicker.$connector) { 41 | return; 42 | } 43 | 44 | timepicker.$connector = {}; 45 | 46 | timepicker.$connector.setLocale = (locale) => { 47 | // capture previous value if any 48 | let previousValueObject; 49 | if (timepicker.value && timepicker.value !== '') { 50 | previousValueObject = parseISO(timepicker.value); 51 | } 52 | 53 | try { 54 | // Check whether the locale is supported by the browser or not 55 | TEST_PM_TIME.toLocaleTimeString(locale); 56 | } catch (e) { 57 | locale = 'en-US'; 58 | // FIXME should do a callback for server to throw an exception ? 59 | throw new Error( 60 | 'vaadin-time-picker: The locale ' + locale + ' is not supported, falling back to default locale setting(en-US).' 61 | ); 62 | } 63 | 64 | // 1. 24 or 12 hour clock, if latter then what are the am/pm strings ? 65 | const pmString = getPmString(locale); 66 | const amString = getAmString(locale); 67 | 68 | // 2. What is the separator ? 69 | const separator = getSeparator(locale); 70 | 71 | const includeSeconds = function () { 72 | return timepicker.step && timepicker.step < 60; 73 | }; 74 | 75 | const includeMilliSeconds = function () { 76 | return timepicker.step && timepicker.step < 1; 77 | }; 78 | 79 | let cachedTimeString; 80 | let cachedTimeObject; 81 | 82 | timepicker.i18n = { 83 | formatTime(timeObject) { 84 | if (!timeObject) return; 85 | 86 | const timeToBeFormatted = new Date(); 87 | timeToBeFormatted.setHours(timeObject.hours); 88 | timeToBeFormatted.setMinutes(timeObject.minutes); 89 | timeToBeFormatted.setSeconds(timeObject.seconds !== undefined ? timeObject.seconds : 0); 90 | 91 | // the web component expects the correct granularity used for the time string, 92 | // thus need to format the time object in correct granularity by passing the format options 93 | let localeTimeString = timeToBeFormatted.toLocaleTimeString(locale, { 94 | hour: 'numeric', 95 | minute: 'numeric', 96 | second: includeSeconds() ? 'numeric' : undefined 97 | }); 98 | 99 | // milliseconds not part of the time format API 100 | if (includeMilliSeconds()) { 101 | localeTimeString = formatMilliseconds(localeTimeString, timeObject.milliseconds, amString, pmString); 102 | } 103 | 104 | return localeTimeString; 105 | }, 106 | 107 | parseTime(timeString) { 108 | if (timeString && timeString === cachedTimeString && cachedTimeObject) { 109 | return cachedTimeObject; 110 | } 111 | 112 | if (!timeString) { 113 | // when nothing is returned, the component shows the invalid state for the input 114 | return; 115 | } 116 | 117 | const amToken = searchAmOrPmToken(timeString, amString); 118 | const pmToken = searchAmOrPmToken(timeString, pmString); 119 | 120 | const numbersOnlyTimeString = timeString 121 | .replace(amToken || '', '') 122 | .replace(pmToken || '', '') 123 | .trim(); 124 | 125 | // A regexp that allows to find the numbers with optional separator and continuing searching after it. 126 | const numbersRegExp = new RegExp('([\\d\\u0660-\\u0669]){1,2}(?:' + separator + ')?', 'g'); 127 | 128 | let hours = numbersRegExp.exec(numbersOnlyTimeString); 129 | if (hours) { 130 | hours = parseDigitsIntoInteger(hours[0].replace(separator, '')); 131 | // handle 12 am -> 0 132 | // do not do anything if am & pm are not used or if those are the same, 133 | // as with locale bg-BG there is always ч. at the end of the time 134 | if (amToken !== pmToken) { 135 | if (hours === 12 && amToken) { 136 | hours = 0; 137 | } 138 | if (hours !== 12 && pmToken) { 139 | hours += 12; 140 | } 141 | } 142 | const minutes = numbersRegExp.exec(numbersOnlyTimeString); 143 | const seconds = minutes && numbersRegExp.exec(numbersOnlyTimeString); 144 | // detecting milliseconds from input, expects am/pm removed from end, eg. .0 or .00 or .000 145 | const millisecondRegExp = /[[\.][\d\u0660-\u0669]{1,3}$/; 146 | // reset to end or things can explode 147 | let milliseconds = seconds && includeMilliSeconds() && millisecondRegExp.exec(numbersOnlyTimeString); 148 | // handle case where last numbers are seconds and . is the separator (invalid regexp match) 149 | if (milliseconds && milliseconds['index'] <= seconds['index']) { 150 | milliseconds = undefined; 151 | } 152 | // hours is a number at this point, others are either arrays or null 153 | // the string in [0] from the arrays includes the separator too 154 | cachedTimeObject = hours !== undefined && { 155 | hours: hours, 156 | minutes: minutes ? parseDigitsIntoInteger(minutes[0].replace(separator, '')) : 0, 157 | seconds: seconds ? parseDigitsIntoInteger(seconds[0].replace(separator, '')) : 0, 158 | milliseconds: 159 | minutes && seconds && milliseconds ? parseMillisecondsIntoInteger(milliseconds[0].replace('.', '')) : 0 160 | }; 161 | cachedTimeString = timeString; 162 | return cachedTimeObject; 163 | } 164 | } 165 | }; 166 | 167 | if (previousValueObject) { 168 | when( 169 | () => timepicker.$, 170 | () => { 171 | const newValue = timepicker.i18n.formatTime(previousValueObject); 172 | // FIXME works but uses private API, needs fixes in web component 173 | if (timepicker.inputElement.value !== newValue) { 174 | timepicker.inputElement.value = newValue; 175 | timepicker.$.comboBox.value = newValue; 176 | } 177 | } 178 | ); 179 | } 180 | }; 181 | }; 182 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/jar-resources/virtualListConnector.js: -------------------------------------------------------------------------------- 1 | import { Debouncer } from '@polymer/polymer/lib/utils/debounce.js'; 2 | import { timeOut } from '@polymer/polymer/lib/utils/async.js'; 3 | 4 | window.Vaadin.Flow.virtualListConnector = { 5 | initLazy: function (list) { 6 | // Check whether the connector was already initialized for the virtual list 7 | if (list.$connector) { 8 | return; 9 | } 10 | 11 | const extraItemsBuffer = 20; 12 | 13 | let lastRequestedRange = [0, 0]; 14 | 15 | list.$connector = {}; 16 | list.$connector.placeholderItem = { __placeholder: true }; 17 | 18 | const updateRequestedItem = function () { 19 | /* 20 | * TODO virtual list seems to do a small index adjustment after scrolling 21 | * has stopped. This causes a redundant request to be sent to make a 22 | * corresponding minimal change to the buffer. We should avoid these 23 | * requests by making the logic skip doing a request if the available 24 | * buffer is within some tolerance compared to the requested buffer. 25 | */ 26 | const visibleIndexes = [...list.children] 27 | .filter((el) => '__virtualListIndex' in el) 28 | .map((el) => el.__virtualListIndex); 29 | const firstNeededItem = Math.min(...visibleIndexes); 30 | const lastNeededItem = Math.max(...visibleIndexes); 31 | 32 | let first = Math.max(0, firstNeededItem - extraItemsBuffer); 33 | let last = Math.min(lastNeededItem + extraItemsBuffer, list.items.length); 34 | 35 | if (lastRequestedRange[0] != first || lastRequestedRange[1] != last) { 36 | lastRequestedRange = [first, last]; 37 | const count = 1 + last - first; 38 | list.$server.setRequestedRange(first, count); 39 | } 40 | }; 41 | 42 | const scheduleUpdateRequest = function () { 43 | list.__requestDebounce = Debouncer.debounce(list.__requestDebounce, timeOut.after(50), updateRequestedItem); 44 | }; 45 | 46 | requestAnimationFrame(() => updateRequestedItem); 47 | 48 | // Add an observer function that will invoke on virtualList.renderer property 49 | // change and then patches it with a wrapper renderer 50 | list.patchVirtualListRenderer = function () { 51 | if (!list.renderer || list.renderer.__virtualListConnectorPatched) { 52 | // The list either doesn't have a renderer yet or it's already been patched 53 | return; 54 | } 55 | 56 | const originalRenderer = list.renderer; 57 | 58 | const renderer = (root, list, model) => { 59 | root.__virtualListIndex = model.index; 60 | 61 | if (model.item === undefined) { 62 | if (list.$connector.placeholderElement) { 63 | // ComponentRenderer 64 | if (!root.__hasComponentRendererPlaceholder) { 65 | // The root was previously rendered by the ComponentRenderer. Clear and add a placeholder. 66 | root.innerHTML = ''; 67 | delete root._$litPart$; 68 | root.appendChild(list.$connector.placeholderElement.cloneNode(true)); 69 | root.__hasComponentRendererPlaceholder = true; 70 | } 71 | } else { 72 | // LitRenderer 73 | originalRenderer.call(list, root, list, { 74 | ...model, 75 | item: list.$connector.placeholderItem 76 | }); 77 | } 78 | } else { 79 | if (root.__hasComponentRendererPlaceholder) { 80 | // The root was previously populated with a placeholder. Clear it. 81 | root.innerHTML = ''; 82 | root.__hasComponentRendererPlaceholder = false; 83 | } 84 | 85 | originalRenderer.call(list, root, list, model); 86 | } 87 | 88 | /* 89 | * Check if we need to do anything once things have settled down. 90 | * This method is called multiple times in sequence for the same user 91 | * action, but we only want to do the check once. 92 | */ 93 | scheduleUpdateRequest(); 94 | }; 95 | renderer.__virtualListConnectorPatched = true; 96 | renderer.__rendererId = originalRenderer.__rendererId; 97 | 98 | list.renderer = renderer; 99 | }; 100 | 101 | list._createPropertyObserver('renderer', 'patchVirtualListRenderer', true); 102 | list.patchVirtualListRenderer(); 103 | 104 | list.items = []; 105 | 106 | list.$connector.set = function (index, items) { 107 | list.items.splice(index, items.length, ...items); 108 | list.items = [...list.items]; 109 | }; 110 | 111 | list.$connector.clear = function (index, length) { 112 | // How many items, starting from "index", should be set as undefined 113 | const clearCount = Math.min(length, list.items.length - index); 114 | list.$connector.set(index, [...Array(clearCount)]); 115 | }; 116 | 117 | list.$connector.updateData = function (items) { 118 | const updatedItemsMap = items.reduce((map, item) => { 119 | map[item.key] = item; 120 | return map; 121 | }, {}); 122 | 123 | list.items = list.items.map((item) => { 124 | // Items can be undefined if they are outside the viewport 125 | if (!item) { 126 | return item; 127 | } 128 | // Replace existing item with updated item, 129 | // return existing item as fallback if it was not updated 130 | return updatedItemsMap[item.key] || item; 131 | }); 132 | }; 133 | 134 | list.$connector.updateSize = function (newSize) { 135 | const delta = newSize - list.items.length; 136 | if (delta > 0) { 137 | list.items = [...list.items, ...Array(delta)]; 138 | } else if (delta < 0) { 139 | list.items = list.items.slice(0, newSize); 140 | } 141 | }; 142 | 143 | list.$connector.setPlaceholderItem = function (placeholderItem = {}, appId) { 144 | placeholderItem.__placeholder = true; 145 | list.$connector.placeholderItem = placeholderItem; 146 | const nodeId = Object.entries(placeholderItem).find(([key]) => key.endsWith('_nodeid')); 147 | list.$connector.placeholderElement = nodeId ? Vaadin.Flow.clients[appId].getByNodeId(nodeId[1]) : null; 148 | }; 149 | } 150 | }; 151 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/vaadin-featureflags.js: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | window.Vaadin = window.Vaadin || {}; 3 | window.Vaadin.featureFlags = window.Vaadin.featureFlags || {}; 4 | window.Vaadin.featureFlags.exampleFeatureFlag = false; 5 | window.Vaadin.featureFlags.collaborationEngineBackend = false; 6 | window.Vaadin.featureFlags.formFillerAddon = false; 7 | window.Vaadin.featureFlags.hillaI18n = false; 8 | window.Vaadin.featureFlags.fullstackSignals = false; 9 | window.Vaadin.featureFlags.copilotExperimentalFeatures = false; 10 | window.Vaadin.featureFlags.dashboardComponent = false; 11 | export {}; -------------------------------------------------------------------------------- /vaadin-sessions/frontend/generated/vaadin.ts: -------------------------------------------------------------------------------- 1 | import 'Frontend/generated/jar-resources/copilot.js'; 2 | // @ts-ignore 3 | if (import.meta.hot) { 4 | // @ts-ignore 5 | import.meta.hot.on('vite:afterUpdate', () => { 6 | const eventbus = (window as any).Vaadin.copilot.eventbus; 7 | if (eventbus) { 8 | eventbus.emit('vite-after-update',{}); 9 | } 10 | }); 11 | } 12 | 13 | import '@vaadin/vertical-layout/theme/lumo/vaadin-vertical-layout.js'; 14 | import '@vaadin/horizontal-layout/theme/lumo/vaadin-horizontal-layout.js'; 15 | import '@vaadin/context-menu/theme/lumo/vaadin-context-menu.js'; 16 | import '@vaadin/checkbox/theme/lumo/vaadin-checkbox.js'; 17 | import '@vaadin/text-field/theme/lumo/vaadin-text-field.js'; 18 | import '@vaadin/text-area/theme/lumo/vaadin-text-area.js'; 19 | import '@vaadin/menu-bar/theme/lumo/vaadin-menu-bar.js'; 20 | import '@vaadin/grid/theme/lumo/vaadin-grid.js'; 21 | import '@vaadin/grid/theme/lumo/vaadin-grid-tree-column.js'; 22 | import '@vaadin/details/theme/lumo/vaadin-details.js'; 23 | import '@vaadin/select/theme/lumo/vaadin-select.js'; 24 | import '@vaadin/overlay/theme/lumo/vaadin-overlay.js'; 25 | import '@vaadin/list-box/theme/lumo/vaadin-list-box.js'; 26 | import '@vaadin/combo-box/theme/lumo/vaadin-combo-box.js'; 27 | import '@vaadin/item/theme/lumo/vaadin-item.js'; 28 | import '@vaadin/dialog/theme/lumo/vaadin-dialog.js'; 29 | import '@vaadin/multi-select-combo-box/theme/lumo/vaadin-multi-select-combo-box.js'; 30 | import '@vaadin/radio-group/theme/lumo/vaadin-radio-group.js'; 31 | import '@vaadin/icons/vaadin-iconset.js'; 32 | import '@vaadin/icon/vaadin-icon.js'; 33 | import './vaadin-featureflags.js'; 34 | 35 | import './index'; 36 | 37 | import './vaadin-react.js'; 38 | import 'Frontend/generated/jar-resources/vaadin-dev-tools/vaadin-dev-tools.js'; 39 | -------------------------------------------------------------------------------- /vaadin-sessions/frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /vaadin-sessions/mvnw.cmd: -------------------------------------------------------------------------------- 1 | <# : batch portion 2 | @REM ---------------------------------------------------------------------------- 3 | @REM Licensed to the Apache Software Foundation (ASF) under one 4 | @REM or more contributor license agreements. See the NOTICE file 5 | @REM distributed with this work for additional information 6 | @REM regarding copyright ownership. The ASF licenses this file 7 | @REM to you under the Apache License, Version 2.0 (the 8 | @REM "License"); you may not use this file except in compliance 9 | @REM with the License. You may obtain a copy of the License at 10 | @REM 11 | @REM https://www.apache.org/licenses/LICENSE-2.0 12 | @REM 13 | @REM Unless required by applicable law or agreed to in writing, 14 | @REM software distributed under the License is distributed on an 15 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | @REM KIND, either express or implied. See the License for the 17 | @REM specific language governing permissions and limitations 18 | @REM under the License. 19 | @REM ---------------------------------------------------------------------------- 20 | 21 | @REM ---------------------------------------------------------------------------- 22 | @REM Apache Maven Wrapper startup batch script, version 3.3.1 23 | @REM 24 | @REM Optional ENV vars 25 | @REM MVNW_REPOURL - repo url base for downloading maven distribution 26 | @REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven 27 | @REM MVNW_VERBOSE - true: enable verbose log; others: silence the output 28 | @REM ---------------------------------------------------------------------------- 29 | 30 | @IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) 31 | @SET __MVNW_CMD__= 32 | @SET __MVNW_ERROR__= 33 | @SET __MVNW_PSMODULEP_SAVE=%PSModulePath% 34 | @SET PSModulePath= 35 | @FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( 36 | IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) 37 | ) 38 | @SET PSModulePath=%__MVNW_PSMODULEP_SAVE% 39 | @SET __MVNW_PSMODULEP_SAVE= 40 | @SET __MVNW_ARG0_NAME__= 41 | @SET MVNW_USERNAME= 42 | @SET MVNW_PASSWORD= 43 | @IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) 44 | @echo Cannot start maven from wrapper >&2 && exit /b 1 45 | @GOTO :EOF 46 | : end batch / begin powershell #> 47 | 48 | $ErrorActionPreference = "Stop" 49 | if ($env:MVNW_VERBOSE -eq "true") { 50 | $VerbosePreference = "Continue" 51 | } 52 | 53 | # calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties 54 | $distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl 55 | if (!$distributionUrl) { 56 | Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" 57 | } 58 | 59 | switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { 60 | "maven-mvnd-*" { 61 | $USE_MVND = $true 62 | $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" 63 | $MVN_CMD = "mvnd.cmd" 64 | break 65 | } 66 | default { 67 | $USE_MVND = $false 68 | $MVN_CMD = $script -replace '^mvnw','mvn' 69 | break 70 | } 71 | } 72 | 73 | # apply MVNW_REPOURL and calculate MAVEN_HOME 74 | # maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ 75 | if ($env:MVNW_REPOURL) { 76 | $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } 77 | $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" 78 | } 79 | $distributionUrlName = $distributionUrl -replace '^.*/','' 80 | $distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' 81 | $MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" 82 | $MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' 83 | $MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" 84 | 85 | if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { 86 | Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" 87 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" 88 | exit $? 89 | } 90 | 91 | if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { 92 | Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" 93 | } 94 | 95 | # prepare tmp dir 96 | $TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile 97 | $TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" 98 | $TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null 99 | trap { 100 | if ($TMP_DOWNLOAD_DIR.Exists) { 101 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } 102 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } 103 | } 104 | } 105 | 106 | New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null 107 | 108 | # Download and Install Apache Maven 109 | Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." 110 | Write-Verbose "Downloading from: $distributionUrl" 111 | Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" 112 | 113 | $webclient = New-Object System.Net.WebClient 114 | if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { 115 | $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) 116 | } 117 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 118 | $webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null 119 | 120 | # If specified, validate the SHA-256 sum of the Maven distribution zip file 121 | $distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum 122 | if ($distributionSha256Sum) { 123 | if ($USE_MVND) { 124 | Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." 125 | } 126 | Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash 127 | if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { 128 | Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." 129 | } 130 | } 131 | 132 | # unzip and move 133 | Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null 134 | Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null 135 | try { 136 | Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null 137 | } catch { 138 | if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { 139 | Write-Error "fail to move MAVEN_HOME" 140 | } 141 | } finally { 142 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } 143 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } 144 | } 145 | 146 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" 147 | -------------------------------------------------------------------------------- /vaadin-sessions/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.4.3 9 | 10 | 11 | dev.danvega 12 | sessions 13 | 0.0.1-SNAPSHOT 14 | sessions 15 | Demo project for Spring Boot 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 23 31 | 24.6.6 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-actuator 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-web 41 | 42 | 43 | com.vaadin 44 | vaadin-spring-boot-starter 45 | 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-devtools 50 | runtime 51 | true 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-starter-test 56 | test 57 | 58 | 59 | 60 | 61 | 62 | com.vaadin 63 | vaadin-bom 64 | ${vaadin.version} 65 | pom 66 | import 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | org.springframework.boot 75 | spring-boot-maven-plugin 76 | 77 | 78 | 79 | 80 | 81 | 82 | production 83 | 84 | 85 | com.vaadin 86 | vaadin-core 87 | 88 | 89 | com.vaadin 90 | vaadin-dev 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | com.vaadin 100 | vaadin-maven-plugin 101 | ${vaadin.version} 102 | 103 | 104 | frontend 105 | compile 106 | 107 | prepare-frontend 108 | build-frontend 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /vaadin-sessions/src/main/java/dev/danvega/vaadin_sessions/Application.java: -------------------------------------------------------------------------------- 1 | package dev.danvega.vaadin_sessions; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /vaadin-sessions/src/main/java/dev/danvega/vaadin_sessions/Session.java: -------------------------------------------------------------------------------- 1 | package dev.danvega.vaadin_sessions; 2 | 3 | import java.util.List; 4 | 5 | public record Session(String title, List speakers) { 6 | } 7 | -------------------------------------------------------------------------------- /vaadin-sessions/src/main/java/dev/danvega/vaadin_sessions/SessionRepository.java: -------------------------------------------------------------------------------- 1 | package dev.danvega.vaadin_sessions; 2 | 3 | import com.fasterxml.jackson.core.type.TypeReference; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import jakarta.annotation.PostConstruct; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.stereotype.Repository; 9 | 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | @Repository 16 | public class SessionRepository { 17 | 18 | private static final Logger log = LoggerFactory.getLogger(SessionRepository.class); 19 | private final List sessions = new ArrayList<>(); 20 | private final ObjectMapper objectMapper; 21 | 22 | public SessionRepository(ObjectMapper objectMapper) { 23 | this.objectMapper = objectMapper; 24 | } 25 | 26 | public List findAll() { 27 | return sessions; 28 | } 29 | 30 | @PostConstruct 31 | private void init() { 32 | 33 | if(sessions.isEmpty()) { 34 | try (InputStream inputStream = TypeReference.class.getResourceAsStream("/data/sessions.json")) { 35 | Sessions allSessions = objectMapper.readValue(inputStream, Sessions.class); 36 | log.info("Reading {} sessions from JSON data", allSessions.sessions().size()); 37 | sessions.addAll(allSessions.sessions()); 38 | } catch (IOException e) { 39 | throw new RuntimeException("Failed to read JSON data", e); 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /vaadin-sessions/src/main/java/dev/danvega/vaadin_sessions/SessionView.java: -------------------------------------------------------------------------------- 1 | package dev.danvega.vaadin_sessions; 2 | 3 | import com.vaadin.flow.component.grid.Grid; 4 | import com.vaadin.flow.component.grid.GridVariant; 5 | import com.vaadin.flow.component.html.H1; 6 | import com.vaadin.flow.component.orderedlayout.VerticalLayout; 7 | import com.vaadin.flow.router.Route; 8 | 9 | import java.util.List; 10 | 11 | @Route("") 12 | public class SessionView extends VerticalLayout { 13 | 14 | public SessionView(SessionRepository repository) { 15 | 16 | // Set the layout properties to center the content 17 | setSizeFull(); 18 | setDefaultHorizontalComponentAlignment(Alignment.CENTER); 19 | 20 | // Title 21 | H1 title = new H1("JavaOne 2025 Sessions"); 22 | 23 | // Grid 24 | Grid grid = new Grid<>(Session.class,false); 25 | grid.addColumn(Session::title) 26 | .setHeader("Title"); 27 | grid.addColumn(Session::speakers) 28 | .setHeader("Speaker(s)"); 29 | grid.addThemeVariants(GridVariant.LUMO_COMPACT);; 30 | 31 | // get data from the repository and add it to the grid 32 | List sessions = repository.findAll(); 33 | grid.setItems(sessions); 34 | 35 | // Container layout for the title and grid with fixed width 36 | VerticalLayout container = new VerticalLayout(title, grid); 37 | container.setHeightFull(); 38 | container.setWidthFull(); 39 | container.setDefaultHorizontalComponentAlignment(Alignment.CENTER); 40 | container.setJustifyContentMode(JustifyContentMode.CENTER); 41 | 42 | add(container); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /vaadin-sessions/src/main/java/dev/danvega/vaadin_sessions/Sessions.java: -------------------------------------------------------------------------------- 1 | package dev.danvega.vaadin_sessions; 2 | 3 | import java.util.List; 4 | 5 | public record Sessions(List sessions) { 6 | } 7 | -------------------------------------------------------------------------------- /vaadin-sessions/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=vaadin-sessions 2 | -------------------------------------------------------------------------------- /vaadin-sessions/src/test/java/dev/danvega/vaadin_sessions/VaadinSessionsApplicationTests.java: -------------------------------------------------------------------------------- 1 | package dev.danvega.vaadin_sessions; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class VaadinSessionsApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /vue-sessions/.env: -------------------------------------------------------------------------------- 1 | VITE_API_URL=http://localhost:8080 -------------------------------------------------------------------------------- /vue-sessions/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /vue-sessions/README.md: -------------------------------------------------------------------------------- 1 | # Vue 3 Sessions 2 | 3 | This is the frontend for the demo that has Vue + Spring Boot in 2 separate applications. To get this to work 4 | you need to have the `spring-mvc-sessions` application running on port `8080`. The reason this works is because of the environment variable set in `.env`. If the Spring Boot application is running on another port you will need to adjust the environment variable. 5 | 6 | ```properties 7 | VITE_API_URL=http://localhost:8080 8 | ``` -------------------------------------------------------------------------------- /vue-sessions/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + Vue 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /vue-sessions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-sessions", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "vue": "^3.4.21" 13 | }, 14 | "devDependencies": { 15 | "@vitejs/plugin-vue": "^5.0.4", 16 | "autoprefixer": "^10.4.19", 17 | "postcss": "^8.4.38", 18 | "tailwindcss": "^3.4.3", 19 | "vite": "^5.2.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /vue-sessions/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /vue-sessions/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vue-sessions/src/App.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | -------------------------------------------------------------------------------- /vue-sessions/src/assets/vue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vue-sessions/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 35 | 36 | 41 | -------------------------------------------------------------------------------- /vue-sessions/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import './style.css' 3 | import App from './App.vue' 4 | 5 | createApp(App).mount('#app') 6 | -------------------------------------------------------------------------------- /vue-sessions/src/style.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /vue-sessions/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: [ 4 | "./index.html", 5 | "./src/**/*.{vue,js,ts,jsx,tsx}", 6 | ], 7 | theme: { 8 | extend: {}, 9 | }, 10 | plugins: [], 11 | } -------------------------------------------------------------------------------- /vue-sessions/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig, loadEnv } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig(({mode}) => { 6 | const env = loadEnv(mode, process.cwd()); 7 | const API_URL = `${env.VITE_API_URL ?? 'http://localhost:8080'}`; 8 | return { 9 | server: { 10 | proxy: { 11 | '/api': { 12 | target: API_URL, 13 | changeOrigin: true 14 | } 15 | } 16 | }, 17 | plugins: [vue()] 18 | }; 19 | }) --------------------------------------------------------------------------------