From f7faa37bebfa5af437253dacf685400eda4727f2 Mon Sep 17 00:00:00 2001 From: Dokkae6949 Date: Sat, 13 Dec 2025 22:59:48 +0100 Subject: [PATCH 01/10] fix: gh-action db 4 --- .github/workflows/docker-image.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 428dfd3..0327d2f 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -60,21 +60,21 @@ jobs: type=sha,prefix={{branch}}- type=raw,value=latest,enable={{is_default_branch}} - - name: Wait for PostgreSQL - run: | - until pg_isready -h localhost -p 5445 -U postgres; do - echo "Waiting for postgres..." - sleep 2 - done + - name: Create Docker network + run: docker network create homepagenetwork || true + + - name: Connect services to network + run: docker network connect homepagenetwork postgres 2>/dev/null || true + - name: Build and publish Docker image uses: docker/build-push-action@v5 with: context: . push: true - network: host + network: homepagenetwork build-args: | - DB_URL=jdbc:postgresql://localhost:5445/homepage + DB_URL=jdbc:postgresql://postgres:5445/homepage DB_USERNAME=postgres DB_PASSWORD=postgres tags: ${{ steps.meta.outputs.tags }} From e798f368512649de310c42ee1d4d080d86dc1546 Mon Sep 17 00:00:00 2001 From: Dokkae6949 Date: Sat, 13 Dec 2025 23:09:11 +0100 Subject: [PATCH 02/10] fix: gh-action db 5 --- .github/workflows/docker-image.yml | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 0327d2f..722c946 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -21,7 +21,7 @@ jobs: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres ports: - - 5445:5432 + - 5432:5432 options: >- --health-cmd="pg_isready -U postgres" --health-interval=5s @@ -39,6 +39,8 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 + with: + driver-opts: network=host - name: Log in to GitHub Container Registry uses: docker/login-action@v3 @@ -60,21 +62,13 @@ jobs: type=sha,prefix={{branch}}- type=raw,value=latest,enable={{is_default_branch}} - - name: Create Docker network - run: docker network create homepagenetwork || true - - - name: Connect services to network - run: docker network connect homepagenetwork postgres 2>/dev/null || true - - - name: Build and publish Docker image uses: docker/build-push-action@v5 with: context: . push: true - network: homepagenetwork build-args: | - DB_URL=jdbc:postgresql://postgres:5445/homepage + DB_URL=jdbc:postgresql://localhost:5432/homepage DB_USERNAME=postgres DB_PASSWORD=postgres tags: ${{ steps.meta.outputs.tags }} From 51cea5d0fe8c96788ab741fafdb89cac8fd15cbf Mon Sep 17 00:00:00 2001 From: Dokkae6949 Date: Sat, 13 Dec 2025 23:33:17 +0100 Subject: [PATCH 03/10] feat: move codegen out of docker builder --- .github/workflows/docker-image.yml | 4 ---- .gitignore | 4 ++++ Dockerfile | 15 ++++++--------- build.gradle.kts | 4 ---- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 722c946..1c21d63 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -67,10 +67,6 @@ jobs: with: context: . push: true - build-args: | - DB_URL=jdbc:postgresql://localhost:5432/homepage - DB_USERNAME=postgres - DB_PASSWORD=postgres tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha diff --git a/.gitignore b/.gitignore index 0e0ad97..a0a695a 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,10 @@ replay_pid* **/build/ !**/src/**/build/ +# Allow generated code fragments for Docker builds +!build/generated-src/ +!build/generated-resources/ + # Ignore Gradle GUI config gradle-app.setting diff --git a/Dockerfile b/Dockerfile index 8afe2ae..8e2c09b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,6 @@ # --- Stage 1: Build the JAR --- FROM gradle:9.2.1-jdk21 AS build -ARG DB_URL -ARG DB_USERNAME -ARG DB_PASSWORD -ENV DB_URL=${DB_URL} -ENV DB_USERNAME=${DB_USERNAME} -ENV DB_PASSWORD=${DB_PASSWORD} - # Set working dir WORKDIR /app @@ -18,8 +11,12 @@ COPY --chown=gradle:gradle gradle ./gradle # Copy source code COPY --chown=gradle:gradle src ./src -# Build the fat jar -RUN ./gradlew clean build --no-daemon +# Copy pre-generated code fragments +COPY --chown=gradle:gradle build/generated-src ./build/generated-src +COPY --chown=gradle:gradle build/generated-resources ./build/generated-resources + +# Build the fat jar without cleaning (preserves generated code) +RUN ./gradlew build -x clean -x cleanGenerated -x jooqCodegen -x flywayMigrate -x precompileJte --no-daemon # --- Stage 2: Run the app --- FROM eclipse-temurin:21-jdk-alpine diff --git a/build.gradle.kts b/build.gradle.kts index 2181e03..9847905 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -295,8 +295,4 @@ tasks.register("cleanGenerated") { delete(generatedSourcesDir) logger.lifecycle("✓ Cleaned generated code directories") } -} - -tasks.named("clean") { - dependsOn("cleanGenerated") } \ No newline at end of file From 5eb6fc4f781288236de53d0e67bb7b87fdbddb6d Mon Sep 17 00:00:00 2001 From: Dokkae6949 Date: Sat, 13 Dec 2025 23:38:15 +0100 Subject: [PATCH 04/10] fix: wronng gitignore exception for codegen --- .gitignore | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index a0a695a..1fee1ef 100644 --- a/.gitignore +++ b/.gitignore @@ -38,10 +38,6 @@ replay_pid* **/build/ !**/src/**/build/ -# Allow generated code fragments for Docker builds -!build/generated-src/ -!build/generated-resources/ - # Ignore Gradle GUI config gradle-app.setting @@ -60,6 +56,10 @@ gradle-app.setting # JDT-specific (Eclipse Java Development Tools) .classpath +# Allow generated code fragments for Docker builds +!build/generated-src/** +!build/generated-resources/** + ################### ### Environment ### ################### From df1870121fd78a97b0c920f26406662199894424 Mon Sep 17 00:00:00 2001 From: Dokkae6949 Date: Sat, 13 Dec 2025 23:40:19 +0100 Subject: [PATCH 05/10] feat: add codegen files --- .../jte/META-INF/main.kotlin_module | Bin 0 -> 24 bytes .../JteIndexGenerated$Companion.class | Bin 0 -> 7863 bytes .../precompiled/JteIndexGenerated.class | Bin 0 -> 2178 bytes .../precompiled/JteIndexGenerated.kt | 24 +++ .../JteMessageGenerated$Companion.class | Bin 0 -> 3124 bytes .../partials/JteMessageGenerated.class | Bin 0 -> 2220 bytes .../partials/JteMessageGenerated.kt | 26 +++ .../homepage/generated/jooq/DefaultCatalog.kt | 43 ++++ .../dokkae/homepage/generated/jooq/Public.kt | 40 ++++ .../homepage/generated/jooq/keys/Keys.kt | 21 ++ .../homepage/generated/jooq/tables/Message.kt | 187 ++++++++++++++++++ .../generated/jooq/tables/pojos/Message.kt | 76 +++++++ .../jooq/tables/records/MessageRecord.kt | 73 +++++++ .../jooq/tables/references/Tables.kt | 15 ++ 14 files changed, 505 insertions(+) create mode 100644 build/generated-resources/jte/META-INF/main.kotlin_module create mode 100644 build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated$Companion.class create mode 100644 build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated.class create mode 100644 build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated.kt create mode 100644 build/generated-resources/jte/gg/jte/generated/precompiled/partials/JteMessageGenerated$Companion.class create mode 100644 build/generated-resources/jte/gg/jte/generated/precompiled/partials/JteMessageGenerated.class create mode 100644 build/generated-resources/jte/gg/jte/generated/precompiled/partials/JteMessageGenerated.kt create mode 100644 build/generated-src/jooq/at/dokkae/homepage/generated/jooq/DefaultCatalog.kt create mode 100644 build/generated-src/jooq/at/dokkae/homepage/generated/jooq/Public.kt create mode 100644 build/generated-src/jooq/at/dokkae/homepage/generated/jooq/keys/Keys.kt create mode 100644 build/generated-src/jooq/at/dokkae/homepage/generated/jooq/tables/Message.kt create mode 100644 build/generated-src/jooq/at/dokkae/homepage/generated/jooq/tables/pojos/Message.kt create mode 100644 build/generated-src/jooq/at/dokkae/homepage/generated/jooq/tables/records/MessageRecord.kt create mode 100644 build/generated-src/jooq/at/dokkae/homepage/generated/jooq/tables/references/Tables.kt diff --git a/build/generated-resources/jte/META-INF/main.kotlin_module b/build/generated-resources/jte/META-INF/main.kotlin_module new file mode 100644 index 0000000000000000000000000000000000000000..9dbc290d21e8fd8815939343a7a5484dc57cfcde GIT binary patch literal 24 ZcmZQzU|?ooU|?ckU|?i`0wo451^@wK08;<} literal 0 HcmV?d00001 diff --git a/build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated$Companion.class b/build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated$Companion.class new file mode 100644 index 0000000000000000000000000000000000000000..8cd23688daa5987dfe4dcaf44666dadefb7196d3 GIT binary patch literal 7863 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 Km?5s1p%wu1UqDa* literal 0 HcmV?d00001 diff --git a/build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated.class b/build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated.class new file mode 100644 index 0000000000000000000000000000000000000000..f31a6e92c0fda11dbcc0b35ff01f0dadef7e44c7 GIT binary patch literal 2178 zcmX^0Z`VEs1_l!bZ$<{a^mP5Kl2rZl)V$Q9#FEq${eq&@ z3U`<+I|CylgFsedS)zVUVqUtwe^ORzatS*FGb00=O=ezZi5(*Yvxa6E4+AR$8y5o$ z13M!FOG!p%F(ZS44{26eGcvFhrRJri7BMoUXuvdQl;q~X$(E7wdz4XssE>$iSHe zGmnu$D61qDWDk-#j0~)~`6;P6j0|Ev+4&_onR)tIWx4uZWx2s6i6xoI){G3wKKVuI z`dO(ZNkxg7dBysPd3pIDx%|9heZTw?ztWr>YeohYe5y)wauSnrQmq*oIGyuz3lj4( z^Ya)PtY97_GNM%AdaZdFgc(FQ8JHME85t}{ivxry>O4BQMnTnrKnl8g)rFz4Wk z4@L%A3?)cG2@V7zVug``6Osme6AKs_{3%QZ;B;GBl9{9Ln^*vj@iJ~LLzyu-~K?DOM17kKL15-sN zh-bjaz?5Rh$e?zhfrpDpf{BYs;6MWx69==zfd&N@BPIhzD@GP4_Ct%L+# zQ3xp0fx;s{IWZ?Ju_zP7hYCtU%?iU}k_uD~ZchLxVpB^}i%={S@J%hr$WMVw7Bez% z24|+{C6<&Hr7|+`c;@A$7CGl678j=$Gcs@m=a&{Gr@Ce4q%s&XFfp(&FfcGPNP;pl z10#bY0|Nsa10#bV0|SF3D6*hpTntPM#taNlaeW2@EaEH-jG&^Kfsw(9fq_9E6bB3p z46It)88|kAVu!&QYB&P}3xf*-0|O5OBS--QCj%GQI&KCY1{Sbp4+a(nP|R^{Vi42P z*4f4&g=zvPgAmvR1&AsJUIu9f5a43qV~_!x%EiFXAj`nS;0m=KFj zMg}1UP#lAN>dwHxz{||Q%fP_E$H2hA4|a_lgFFK(cGoDQyGD$lYZMt&7?>D5z~P`k zma7yQ7#KJhRKd{$3gA5qAg?emEZEH;5y`lnL1Qz6n2^?H20a0ZJzU;e%*_5;EX@8| ztjzveY^?rT?5zG;9IXCY0w9h6h$p}y;NY(%zzHU~1Q~k$wFI~!6ptW7pTCv>FNER~ zWa#(T65xkW0)hjh lV9sFW$zaW36V1R_%wWr47tO$0%)nL5U|$SkuoW{10|0PP0|@{C literal 0 HcmV?d00001 diff --git a/build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated.kt b/build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated.kt new file mode 100644 index 0000000..3b1fa73 --- /dev/null +++ b/build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated.kt @@ -0,0 +1,24 @@ +@file:Suppress("ktlint") +package gg.jte.generated.precompiled +import at.dokkae.homepage.templates.Index +@Suppress("UNCHECKED_CAST", "UNUSED_PARAMETER") +class JteIndexGenerated { +companion object { + @JvmField val JTE_NAME = "Index.kte" + @JvmField val JTE_LINE_INFO = intArrayOf(0,0,0,2,2,2,2,2,64,64,141,141,142,142,143,143,158,158,158,2,2,2,2,2) + @JvmStatic fun render(jteOutput:gg.jte.html.HtmlTemplateOutput, jteHtmlInterceptor:gg.jte.html.HtmlInterceptor?, model:Index) { + jteOutput.writeContent("\n\n\n\n \n \n Simple Chat — http4k + JTE + htmx\n\n \n \n\n \n\n\n
\n

Simple Chat

\n\n
\n ") + for (message in model.messages.reversed()) { + jteOutput.writeContent("\n ") + gg.jte.generated.precompiled.partials.JteMessageGenerated.render(jteOutput, jteHtmlInterceptor, message); + jteOutput.writeContent("\n ") + } + jteOutput.writeContent("\n
\n\n\n
\n \n \n \n
\n\n

No auth — anyone can post. Messages are stored only in memory.

\n
\n\n") + } + @JvmStatic fun renderMap(jteOutput:gg.jte.html.HtmlTemplateOutput, jteHtmlInterceptor:gg.jte.html.HtmlInterceptor?, params:Map) { + val model = params["model"] as Index + render(jteOutput, jteHtmlInterceptor, model); + } +} +} diff --git a/build/generated-resources/jte/gg/jte/generated/precompiled/partials/JteMessageGenerated$Companion.class b/build/generated-resources/jte/gg/jte/generated/precompiled/partials/JteMessageGenerated$Companion.class new file mode 100644 index 0000000000000000000000000000000000000000..7f497996c573798f3b938b1891f352889c1932c1 GIT binary patch literal 3124 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 literal 0 HcmV?d00001 diff --git a/build/generated-resources/jte/gg/jte/generated/precompiled/partials/JteMessageGenerated.kt b/build/generated-resources/jte/gg/jte/generated/precompiled/partials/JteMessageGenerated.kt new file mode 100644 index 0000000..b93e8e4 --- /dev/null +++ b/build/generated-resources/jte/gg/jte/generated/precompiled/partials/JteMessageGenerated.kt @@ -0,0 +1,26 @@ +@file:Suppress("ktlint") +package gg.jte.generated.precompiled.partials +import at.dokkae.homepage.Message +@Suppress("UNCHECKED_CAST", "UNUSED_PARAMETER") +class JteMessageGenerated { +companion object { + @JvmField val JTE_NAME = "partials/Message.kte" + @JvmField val JTE_LINE_INFO = intArrayOf(0,0,0,2,2,2,2,2,5,5,5,5,6,6,6,8,8,8,10,10,10,2,2,2,2,2) + @JvmStatic fun render(jteOutput:gg.jte.html.HtmlTemplateOutput, jteHtmlInterceptor:gg.jte.html.HtmlInterceptor?, message:Message) { + jteOutput.writeContent("\n
\n ") + jteOutput.setContext("strong", null) + jteOutput.writeUserContent(message.author) + jteOutput.writeContent(":\n ") + jteOutput.setContext("div", null) + jteOutput.writeUserContent(message.content) + jteOutput.writeContent("\n \n (") + jteOutput.setContext("span", null) + jteOutput.writeUserContent(message.createdAt.toString()) + jteOutput.writeContent(")\n \n
") + } + @JvmStatic fun renderMap(jteOutput:gg.jte.html.HtmlTemplateOutput, jteHtmlInterceptor:gg.jte.html.HtmlInterceptor?, params:Map) { + val message = params["message"] as Message + render(jteOutput, jteHtmlInterceptor, message); + } +} +} diff --git a/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/DefaultCatalog.kt b/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/DefaultCatalog.kt new file mode 100644 index 0000000..034f3de --- /dev/null +++ b/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/DefaultCatalog.kt @@ -0,0 +1,43 @@ +/* + * This file is generated by jOOQ. + */ +package at.dokkae.homepage.generated.jooq + + +import kotlin.collections.List + +import org.jooq.Constants +import org.jooq.Schema +import org.jooq.impl.CatalogImpl + + +/** + * This class is generated by jOOQ. + */ +@Suppress("warnings") +open class DefaultCatalog : CatalogImpl("") { + companion object { + + /** + * The reference instance of DEFAULT_CATALOG + */ + val DEFAULT_CATALOG: DefaultCatalog = DefaultCatalog() + } + + /** + * standard public schema + */ + val PUBLIC: Public get(): Public = Public.PUBLIC + + override fun getSchemas(): List = listOf( + Public.PUBLIC + ) + + /** + * A reference to the 3.20 minor release of the code generator. If this + * doesn't compile, it's because the runtime library uses an older minor + * release, namely: 3.20. You can turn off the generation of this reference + * by specifying /configuration/generator/generate/jooqVersionReference + */ + private val REQUIRE_RUNTIME_JOOQ_VERSION = Constants.VERSION_3_20 +} diff --git a/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/Public.kt b/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/Public.kt new file mode 100644 index 0000000..772d0e4 --- /dev/null +++ b/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/Public.kt @@ -0,0 +1,40 @@ +/* + * This file is generated by jOOQ. + */ +package at.dokkae.homepage.generated.jooq + + +import at.dokkae.homepage.generated.jooq.tables.Message + +import kotlin.collections.List + +import org.jooq.Catalog +import org.jooq.Table +import org.jooq.impl.DSL +import org.jooq.impl.SchemaImpl + + +/** + * standard public schema + */ +@Suppress("warnings") +open class Public : SchemaImpl(DSL.name("public"), DefaultCatalog.DEFAULT_CATALOG, DSL.comment("standard public schema")) { + companion object { + + /** + * The reference instance of public + */ + val PUBLIC: Public = Public() + } + + /** + * The table public.message. + */ + val MESSAGE: Message get() = Message.MESSAGE + + override fun getCatalog(): Catalog = DefaultCatalog.DEFAULT_CATALOG + + override fun getTables(): List> = listOf( + Message.MESSAGE + ) +} diff --git a/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/keys/Keys.kt b/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/keys/Keys.kt new file mode 100644 index 0000000..f59d310 --- /dev/null +++ b/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/keys/Keys.kt @@ -0,0 +1,21 @@ +@file:Suppress("warnings") +/* + * This file is generated by jOOQ. + */ +package at.dokkae.homepage.generated.jooq.keys + + +import at.dokkae.homepage.generated.jooq.tables.Message +import at.dokkae.homepage.generated.jooq.tables.records.MessageRecord + +import org.jooq.UniqueKey +import org.jooq.impl.DSL +import org.jooq.impl.Internal + + + +// ------------------------------------------------------------------------- +// UNIQUE and PRIMARY KEY definitions +// ------------------------------------------------------------------------- + +val MESSAGE_PKEY: UniqueKey = Internal.createUniqueKey(Message.MESSAGE, DSL.name("message_pkey"), arrayOf(Message.MESSAGE.ID), true) diff --git a/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/tables/Message.kt b/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/tables/Message.kt new file mode 100644 index 0000000..4801187 --- /dev/null +++ b/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/tables/Message.kt @@ -0,0 +1,187 @@ +/* + * This file is generated by jOOQ. + */ +package at.dokkae.homepage.generated.jooq.tables + + +import at.dokkae.homepage.generated.jooq.Public +import at.dokkae.homepage.generated.jooq.keys.MESSAGE_PKEY +import at.dokkae.homepage.generated.jooq.tables.records.MessageRecord + +import java.time.OffsetDateTime +import java.util.UUID + +import kotlin.collections.Collection + +import org.jooq.Condition +import org.jooq.Field +import org.jooq.ForeignKey +import org.jooq.InverseForeignKey +import org.jooq.Name +import org.jooq.PlainSQL +import org.jooq.QueryPart +import org.jooq.Record +import org.jooq.SQL +import org.jooq.Schema +import org.jooq.Select +import org.jooq.Stringly +import org.jooq.Table +import org.jooq.TableField +import org.jooq.TableOptions +import org.jooq.UniqueKey +import org.jooq.impl.DSL +import org.jooq.impl.SQLDataType +import org.jooq.impl.TableImpl + + +/** + * This class is generated by jOOQ. + */ +@Suppress("warnings") +open class Message( + alias: Name, + path: Table?, + childPath: ForeignKey?, + parentPath: InverseForeignKey?, + aliased: Table?, + parameters: Array?>?, + where: Condition? +): TableImpl( + alias, + Public.PUBLIC, + path, + childPath, + parentPath, + aliased, + parameters, + DSL.comment(""), + TableOptions.table(), + where, +) { + companion object { + + /** + * The reference instance of public.message + */ + val MESSAGE: Message = Message() + } + + /** + * The class holding records for this type + */ + override fun getRecordType(): Class = MessageRecord::class.java + + /** + * The column public.message.id. + */ + val ID: TableField = createField(DSL.name("id"), SQLDataType.UUID.nullable(false), this, "") + + /** + * The column public.message.author. + */ + val AUTHOR: TableField = createField(DSL.name("author"), SQLDataType.VARCHAR(31).nullable(false), this, "") + + /** + * The column public.message.content. + */ + val CONTENT: TableField = createField(DSL.name("content"), SQLDataType.VARCHAR(255).nullable(false), this, "") + + /** + * The column public.message.created_at. + */ + val CREATED_AT: TableField = createField(DSL.name("created_at"), SQLDataType.TIMESTAMPWITHTIMEZONE(6).nullable(false).defaultValue(DSL.field(DSL.raw("CURRENT_TIMESTAMP"), SQLDataType.TIMESTAMPWITHTIMEZONE)), this, "") + + /** + * The column public.message.updated_at. + */ + val UPDATED_AT: TableField = createField(DSL.name("updated_at"), SQLDataType.TIMESTAMPWITHTIMEZONE(6), this, "") + + private constructor(alias: Name, aliased: Table?): this(alias, null, null, null, aliased, null, null) + private constructor(alias: Name, aliased: Table?, parameters: Array?>?): this(alias, null, null, null, aliased, parameters, null) + private constructor(alias: Name, aliased: Table?, where: Condition?): this(alias, null, null, null, aliased, null, where) + + /** + * Create an aliased public.message table reference + */ + constructor(alias: String): this(DSL.name(alias)) + + /** + * Create an aliased public.message table reference + */ + constructor(alias: Name): this(alias, null) + + /** + * Create a public.message table reference + */ + constructor(): this(DSL.name("message"), null) + override fun getSchema(): Schema? = if (aliased()) null else Public.PUBLIC + override fun getPrimaryKey(): UniqueKey = MESSAGE_PKEY + override fun `as`(alias: String): Message = Message(DSL.name(alias), this) + override fun `as`(alias: Name): Message = Message(alias, this) + override fun `as`(alias: Table<*>): Message = Message(alias.qualifiedName, this) + + /** + * Rename this table + */ + override fun rename(name: String): Message = Message(DSL.name(name), null) + + /** + * Rename this table + */ + override fun rename(name: Name): Message = Message(name, null) + + /** + * Rename this table + */ + override fun rename(name: Table<*>): Message = Message(name.qualifiedName, null) + + /** + * Create an inline derived table from this table + */ + override fun where(condition: Condition?): Message = Message(qualifiedName, if (aliased()) this else null, condition) + + /** + * Create an inline derived table from this table + */ + override fun where(conditions: Collection): Message = where(DSL.and(conditions)) + + /** + * Create an inline derived table from this table + */ + override fun where(vararg conditions: Condition?): Message = where(DSL.and(*conditions)) + + /** + * Create an inline derived table from this table + */ + override fun where(condition: Field?): Message = where(DSL.condition(condition)) + + /** + * Create an inline derived table from this table + */ + @PlainSQL override fun where(condition: SQL): Message = where(DSL.condition(condition)) + + /** + * Create an inline derived table from this table + */ + @PlainSQL override fun where(@Stringly.SQL condition: String): Message = where(DSL.condition(condition)) + + /** + * Create an inline derived table from this table + */ + @PlainSQL override fun where(@Stringly.SQL condition: String, vararg binds: Any?): Message = where(DSL.condition(condition, *binds)) + + /** + * Create an inline derived table from this table + */ + @PlainSQL override fun where(@Stringly.SQL condition: String, vararg parts: QueryPart): Message = where(DSL.condition(condition, *parts)) + + /** + * Create an inline derived table from this table + */ + override fun whereExists(select: Select<*>): Message = where(DSL.exists(select)) + + /** + * Create an inline derived table from this table + */ + override fun whereNotExists(select: Select<*>): Message = where(DSL.notExists(select)) +} diff --git a/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/tables/pojos/Message.kt b/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/tables/pojos/Message.kt new file mode 100644 index 0000000..7976170 --- /dev/null +++ b/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/tables/pojos/Message.kt @@ -0,0 +1,76 @@ +/* + * This file is generated by jOOQ. + */ +package at.dokkae.homepage.generated.jooq.tables.pojos + + +import java.io.Serializable +import java.time.OffsetDateTime +import java.util.UUID + + +/** + * This class is generated by jOOQ. + */ +@Suppress("warnings") +data class Message( + val id: UUID, + val author: String, + val content: String, + val createdAt: OffsetDateTime? = null, + val updatedAt: OffsetDateTime? = null +): Serializable { + + override fun equals(other: Any?): Boolean { + if (this === other) + return true + if (other == null) + return false + if (this::class != other::class) + return false + val o: Message = other as Message + if (this.id != o.id) + return false + if (this.author != o.author) + return false + if (this.content != o.content) + return false + if (this.createdAt == null) { + if (o.createdAt != null) + return false + } + else if (this.createdAt != o.createdAt) + return false + if (this.updatedAt == null) { + if (o.updatedAt != null) + return false + } + else if (this.updatedAt != o.updatedAt) + return false + return true + } + + override fun hashCode(): Int { + val prime = 31 + var result = 1 + result = prime * result + this.id.hashCode() + result = prime * result + this.author.hashCode() + result = prime * result + this.content.hashCode() + result = prime * result + (if (this.createdAt == null) 0 else this.createdAt.hashCode()) + result = prime * result + (if (this.updatedAt == null) 0 else this.updatedAt.hashCode()) + return result + } + + override fun toString(): String { + val sb = StringBuilder("Message (") + + sb.append(id) + sb.append(", ").append(author) + sb.append(", ").append(content) + sb.append(", ").append(createdAt) + sb.append(", ").append(updatedAt) + + sb.append(")") + return sb.toString() + } +} diff --git a/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/tables/records/MessageRecord.kt b/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/tables/records/MessageRecord.kt new file mode 100644 index 0000000..fb107a6 --- /dev/null +++ b/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/tables/records/MessageRecord.kt @@ -0,0 +1,73 @@ +/* + * This file is generated by jOOQ. + */ +package at.dokkae.homepage.generated.jooq.tables.records + + +import at.dokkae.homepage.generated.jooq.tables.Message + +import java.time.OffsetDateTime +import java.util.UUID + +import org.jooq.Record1 +import org.jooq.impl.UpdatableRecordImpl + + +/** + * This class is generated by jOOQ. + */ +@Suppress("warnings") +open class MessageRecord private constructor() : UpdatableRecordImpl(Message.MESSAGE) { + + open var id: UUID + set(value): Unit = set(0, value) + get(): UUID = get(0) as UUID + + open var author: String + set(value): Unit = set(1, value) + get(): String = get(1) as String + + open var content: String + set(value): Unit = set(2, value) + get(): String = get(2) as String + + open var createdAt: OffsetDateTime? + set(value): Unit = set(3, value) + get(): OffsetDateTime? = get(3) as OffsetDateTime? + + open var updatedAt: OffsetDateTime? + set(value): Unit = set(4, value) + get(): OffsetDateTime? = get(4) as OffsetDateTime? + + // ------------------------------------------------------------------------- + // Primary key information + // ------------------------------------------------------------------------- + + override fun key(): Record1 = super.key() as Record1 + + /** + * Create a detached, initialised MessageRecord + */ + constructor(id: UUID, author: String, content: String, createdAt: OffsetDateTime? = null, updatedAt: OffsetDateTime? = null): this() { + this.id = id + this.author = author + this.content = content + this.createdAt = createdAt + this.updatedAt = updatedAt + resetTouchedOnNotNull() + } + + /** + * Create a detached, initialised MessageRecord + */ + constructor(value: at.dokkae.homepage.generated.jooq.tables.pojos.Message?): this() { + if (value != null) { + this.id = value.id + this.author = value.author + this.content = value.content + this.createdAt = value.createdAt + this.updatedAt = value.updatedAt + resetTouchedOnNotNull() + } + } +} diff --git a/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/tables/references/Tables.kt b/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/tables/references/Tables.kt new file mode 100644 index 0000000..4feda24 --- /dev/null +++ b/build/generated-src/jooq/at/dokkae/homepage/generated/jooq/tables/references/Tables.kt @@ -0,0 +1,15 @@ +@file:Suppress("warnings") +/* + * This file is generated by jOOQ. + */ +package at.dokkae.homepage.generated.jooq.tables.references + + +import at.dokkae.homepage.generated.jooq.tables.Message + + + +/** + * The table public.message. + */ +val MESSAGE: Message = Message.MESSAGE From 2623ec764338b47ef29e49118ab4e4a194c0ffd3 Mon Sep 17 00:00:00 2001 From: Dokkae6949 Date: Sun, 14 Dec 2025 00:06:42 +0100 Subject: [PATCH 06/10] feat: dokploy deployment api call --- .github/workflows/docker-image.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 1c21d63..68fca5a 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -71,3 +71,20 @@ jobs: labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max + + deploy: + runs-on: ubuntu-latest + needs: build + if: success() + + steps: + - name: Trigger Dokploy deployment + run: | + curl -X 'POST' \ + 'http://5.180.253.47:3000/api/application.deploy' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'x-api-key: ${{ secrets.DOKPLOY_API_KEY }}' \ + -d '{ + "applicationId": "${{ vars.DOKPLOY_APP_ID }}" + }' \ No newline at end of file From b2af414cfb99a064189bea4938b0ecd64db3c78a Mon Sep 17 00:00:00 2001 From: Dokkae6949 Date: Sun, 14 Dec 2025 00:18:51 +0100 Subject: [PATCH 07/10] fix: flyway path resolution issue --- build.gradle.kts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 9847905..defbd59 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -269,10 +269,15 @@ tasks.named("shadowJar") { archiveFileName.set("app.jar") - mergeServiceFiles() + mergeServiceFiles { + include("META-INF/services/**") + + // Fix: https://github.com/flyway/flyway/issues/4170#issuecomment-3569762563 + duplicatesStrategy = DuplicatesStrategy.INCLUDE + } exclude( - "META-INF/*. RSA", + "META-INF/*.RSA", "META-INF/*.SF", "META-INF/*.DSA" ) From 388dc63a1215cdc93309b7b2b80b65a00ea9446b Mon Sep 17 00:00:00 2001 From: Dokkae6949 Date: Sun, 14 Dec 2025 01:00:27 +0100 Subject: [PATCH 08/10] fix: updated_at set to null on insert before it was being set to current_timestamp which was a bug --- .../V003__fix_updated_at_insert_trigger.sql | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/main/resources/db/migration/V003__fix_updated_at_insert_trigger.sql diff --git a/src/main/resources/db/migration/V003__fix_updated_at_insert_trigger.sql b/src/main/resources/db/migration/V003__fix_updated_at_insert_trigger.sql new file mode 100644 index 0000000..a731f95 --- /dev/null +++ b/src/main/resources/db/migration/V003__fix_updated_at_insert_trigger.sql @@ -0,0 +1,35 @@ +--- Dropping trigger to prevent them from being called while migrating data +drop trigger if exists handle_message_timestamps on message; + +--- Migrate data +update message +set updated_at = null +where created_at = updated_at + and updated_at is not null; + +--- Replace trigger handler +create or replace function handle_timestamps() + returns trigger as +$$ +begin + if lower(tg_op) = 'insert' then + new.created_at = coalesce(new.created_at, current_timestamp); + new.updated_at = null; + elsif lower(tg_op) = 'update' then + if new.created_at is distinct from old.created_at then + raise exception 'Direct modification of created_at is not allowed.'; + end if; + + new.updated_at = current_timestamp; + end if; + + return new; +end; +$$ language plpgsql; + +--- Reinsert trigger +create trigger handle_message_timestamps + before insert or update + on message + for each row +execute function handle_timestamps(); \ No newline at end of file From ec7e116a2b714fd45b9da9e3f1656eb0faae0893 Mon Sep 17 00:00:00 2001 From: Dokkae6949 Date: Sun, 14 Dec 2025 03:40:05 +0100 Subject: [PATCH 09/10] feat: ui rework --- .env.example | 5 +- .../JteIndexGenerated$Companion.class | Bin 7863 -> 9727 bytes .../precompiled/JteIndexGenerated.class | Bin 2178 -> 2253 bytes .../precompiled/JteIndexGenerated.kt | 31 ++- .../JteMessageGenerated$Companion.class | Bin 3124 -> 5186 bytes .../partials/JteMessageGenerated.class | Bin 2220 -> 2384 bytes .../partials/JteMessageGenerated.kt | 46 ++-- jte-classes/META-INF/main.kotlin_module | Bin 0 -> 24 bytes .../generated/ondemand/JteIndexGenerated.kt | 35 +++ .../ondemand/partials/JteMessageGenerated.kt | 46 ++++ .../kotlin/at/dokkae/homepage/Homepage.kt | 61 +++-- .../at/dokkae/homepage/config/Environment.kt | 15 +- .../at/dokkae/homepage/templates/Index.kt | 2 +- .../at/dokkae/homepage/templates/Message.kt | 8 + src/main/kte/Index.kte | 221 +++++++++--------- src/main/kte/partials/Message.kte | 40 +++- src/main/resources/static/css/.keep | 0 src/main/resources/static/css/index.css | 0 src/main/resources/static/images/.keep | 0 src/main/resources/static/js/.keep | 0 20 files changed, 341 insertions(+), 169 deletions(-) create mode 100644 jte-classes/META-INF/main.kotlin_module create mode 100644 jte-classes/gg/jte/generated/ondemand/JteIndexGenerated.kt create mode 100644 jte-classes/gg/jte/generated/ondemand/partials/JteMessageGenerated.kt create mode 100644 src/main/kotlin/at/dokkae/homepage/templates/Message.kt create mode 100644 src/main/resources/static/css/.keep create mode 100644 src/main/resources/static/css/index.css create mode 100644 src/main/resources/static/images/.keep create mode 100644 src/main/resources/static/js/.keep diff --git a/.env.example b/.env.example index eb9c21b..71b5d1a 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,6 @@ -PORT=9000 -HOST=localhost +APP_PORT=9000 +APP_DOMAIN=localhost +APP_ENV=development DB_URL=jdbc:postgresql://localhost:5432/homepage DB_USERNAME=postgres diff --git a/build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated$Companion.class b/build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated$Companion.class index 8cd23688daa5987dfe4dcaf44666dadefb7196d3..692b37c5c7342e2f136008629efe4420c086e7c5 100644 GIT binary patch literal 9727 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 Uf?@{#Vur$EhN5DI(qe`w0NTDf3IG5A literal 7863 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 Km?5s1p%wu1UqDa* diff --git a/build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated.class b/build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated.class index f31a6e92c0fda11dbcc0b35ff01f0dadef7e44c7..d3e2cd6757bf082345b66256ed0f1d0f48e0cf1b 100644 GIT binary patch delta 330 zcmZn?JS#Y16JyR~9%lQApOiR4QgaJ(5=&Ayi!c^3GU`nHsEiO=#Z=48$TnGn&5==d zau!=JqvGT&HpR)3>_PS48JHOu85kID?`DvQWZcf6v6(?kNNY2Lo`CWmE^jSnW`8Xf zW`8YKW`8X<7Jn^vR(~xHc7H7aHW0xMBEVcu5Q|Gd$X`o<8%**DsQPOO@CumvYYFfP zc=~Gz@C*3)YY7Ml1p8|V2!cr=fslHCEdgPH5PvNJ5rI&DEdfz5DJBr@uO%QZkm#=^ zAR&aQgrEyys%UrRs+LdilXIgktFL4*Q`Py`W5?EYGt8H_eE iFfcGOI5RLXa4|43a5Hc+2rzIlFf({EFih6t2mt^C5kDCK delta 247 zcmX>r*d#b%6JyF`8D{&5pOiMsFcvW~s!aT-ym=Q>Ei)s_WD7P&Mxn`7Y`u(PldISi zCu_0?)$d_oW?*DsU|6u5K_ZfIJA=k%1~DP6%?x@15_`D3wV0XxwOE+_wOE<`wb)qw zwb)txwK!P)wFE#M0T54sL%_jbOMnwhatSi@`fCYrLnt0WhCY8S0bU5jC&tAqXW5GFk*gh=K?)5FyU$ueF)MXd?py10#bo0|NsW0}}%`13QBN K1IOfIjwk?<&@TS~ diff --git a/build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated.kt b/build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated.kt index 3b1fa73..35daa35 100644 --- a/build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated.kt +++ b/build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated.kt @@ -1,23 +1,34 @@ @file:Suppress("ktlint") package gg.jte.generated.precompiled -import at.dokkae.homepage.templates.Index +import at.dokkae.homepage.templates.IndexTemplate +import at.dokkae.homepage.templates.MessageTemplate +import gg.jte.support.ForSupport @Suppress("UNCHECKED_CAST", "UNUSED_PARAMETER") class JteIndexGenerated { companion object { @JvmField val JTE_NAME = "Index.kte" - @JvmField val JTE_LINE_INFO = intArrayOf(0,0,0,2,2,2,2,2,64,64,141,141,142,142,143,143,158,158,158,2,2,2,2,2) - @JvmStatic fun render(jteOutput:gg.jte.html.HtmlTemplateOutput, jteHtmlInterceptor:gg.jte.html.HtmlInterceptor?, model:Index) { - jteOutput.writeContent("\n\n\n\n \n \n Simple Chat — http4k + JTE + htmx\n\n \n \n\n \n\n\n
\n

Simple Chat

\n\n
\n ") + @JvmField val JTE_LINE_INFO = intArrayOf(0,0,0,1,2,4,4,4,4,4,18,18,37,53,73,78,83,83,84,84,85,85,91,97,108,121,133,148,148,148,4,4,4,4,4) + @JvmStatic fun render(jteOutput:gg.jte.html.HtmlTemplateOutput, jteHtmlInterceptor:gg.jte.html.HtmlInterceptor?, model:IndexTemplate) { + jteOutput.writeContent("\n\n\n\n \n \n Dokkae's Chat\n\n \n \n \n\n \n\n\n
\n ") + jteOutput.writeContent("\n
\n

Simple Chat

\n
\n\n ") + jteOutput.writeContent("\n
\n
\n
\n
\n ") for (message in model.messages.reversed()) { - jteOutput.writeContent("\n ") - gg.jte.generated.precompiled.partials.JteMessageGenerated.render(jteOutput, jteHtmlInterceptor, message); - jteOutput.writeContent("\n ") + jteOutput.writeContent("\n ") + gg.jte.generated.precompiled.partials.JteMessageGenerated.render(jteOutput, jteHtmlInterceptor, MessageTemplate(message)); + jteOutput.writeContent("\n ") } - jteOutput.writeContent("\n
\n\n\n
\n \n \n \n
\n\n

No auth — anyone can post. Messages are stored only in memory.

\n
\n\n") + jteOutput.writeContent("\n
\n \n \n \n\n ") + jteOutput.writeContent("\n
\n
\n ") + jteOutput.writeContent("\n
\n
\n \n
\n
\n\n ") + jteOutput.writeContent("\n
\n
\n \n
\n
\n\n ") + jteOutput.writeContent("\n \n
\n
\n\n ") + jteOutput.writeContent("\n \n
\n\n\n") } @JvmStatic fun renderMap(jteOutput:gg.jte.html.HtmlTemplateOutput, jteHtmlInterceptor:gg.jte.html.HtmlInterceptor?, params:Map) { - val model = params["model"] as Index + val model = params["model"] as IndexTemplate render(jteOutput, jteHtmlInterceptor, model); } } diff --git a/build/generated-resources/jte/gg/jte/generated/precompiled/partials/JteMessageGenerated$Companion.class b/build/generated-resources/jte/gg/jte/generated/precompiled/partials/JteMessageGenerated$Companion.class index 7f497996c573798f3b938b1891f352889c1932c1..e642725ebfd0236cab4307a4386590f18040d638 100644 GIT binary patch literal 5186 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 delta 1247 zcmX@4u| z?`bJ>*`#EaDJ17478lzpL1mQexD*r=6l{u1it_W)?Kl{u85!gzKjfC1T)||<#Rd`P zU{IcXmerD5l|hZ0L5@M4kwI#*AREXUPDahi%^a%r+6+2e3|b7jj0^(hMVTe3p~b01 z&iQ#Isd*(l4EhWTAZ-SW4E#3w5EJdJz}9jw7%?(1r(~9KFqkkhaHXe~z%`jcOf+X? zfGD*oE=bH%C@!hYNwrl<&dhI$F)Ee#F^ zOGXA3kX8-`>&eobnt`?qb|9D9GcpKfC6*=Xmt^Lq>U-uDmn7zuuroL^GH{gS2bUCO z=B4v6ID_2a#NfinAfgF&uZ=#)C_642{gliyI}QdnMh1n+54aU3>vAhG$@oA6g?(}@ z_hTtPMh0H64W%WSIr_ed1?&s~j10`_sU?$3c(l2L7=pPO0vSRW8SE#o;<3>6g~SvG zLl`3iPjW_Ta<*T7iC<|>4i7^FgE$w1C_^L<12+Q?7XuSR^kzj~b|%Jx$(sDn7)vG# z2#D2}GB7Z(F))J3G6n_)9x$7gfs=uYfq_8~q?3V#p@e~f;U)t!0}BHKL#DQn@D2t^ zT_LF*43gSHGCLWRm>9H$R2X+MXfQKq>uzJv+sR-E5;BHLnIfbtpi)*)sd^iPoWnK- zSE#f*Sb8G^0|OHS$c1`fcW^O?FmN--GVm~{Gw?F#Gw?B3Fz_=tF$getF$gjQGYByx zFbFebFo-aKe4+($Ez~Cr44DkP3?5+LWis$Fcrq}7{8G=r&)~(t%uo&v07eD@1_p)- z1_lOUW(GzEK?Vi}Mg}1;31U|=Ffi~kGw?DnFz_)jFz|x|$eY23ffXD;O$;mytPBhc z8n6KJhXm73hEOJkNTKi@3{eLdw5(XPv~?s|wlTzjyjKtLA0GoV0}q23gFJ&cgF1r* z*!?C9tPJuDoL~on!d(OI6AideG~hnbVDMvzWngBg0*9F|u^y^N@sS?`g8(A~D?=Ou zBiKi}42H@W7#O&~nhF_;7$g~Lz^*9< zyC#K!ks*nJl_5Erf!UKG#gie`lOZjDA>ET9l_A5EA(J61nt`#HA)6s5nnAdjfvcDy ux0r#on1QXBArH*X2b0`jlDC+_qnLrOn8CA{fxno+tC+#Nn8B}@Ar}BtuhVM) diff --git a/build/generated-resources/jte/gg/jte/generated/precompiled/partials/JteMessageGenerated.class b/build/generated-resources/jte/gg/jte/generated/precompiled/partials/JteMessageGenerated.class index ea7798fa0d60d11f576b08c04a19b845f8baa431..a51102d1763b658a8b4118c8465ce17c824cab4a 100644 GIT binary patch delta 456 zcmZ1@ctL2w3C6t1TFmy7IT(c{N>XzRauQ2Yi}ig|i;EM}Q$rvElNA}&*;sS)Q&Mv_ z2QbDk>gxFSyHVrWPcor|RROMvci+*?JjuCQoHk zob19LSkGw7z|6qNz`&@un?WLyaXW*?W(F}Kt<4O20(yJ6ytSB_{k2$_{k2$`{k7Ow z{I%Fw{k1sQ{Ivww*!{Hx*abjL4lv0HCb_^QH<;uR;PBTH;02R>V3J>e(_c$K089!B zaQSQ13kZQI0bv0?e=PwK0e*ii0Z}k11}4S9q=bNwzm|ZcfT+KgfE1XN29q)Z68>5O zvS3mUOv-~v1u&@yCY1za{Ivv>1?2p-1XRGJDwtFgQ1aIja8w6V8emcr>}oAAsSPG| lz@#pS+{|FKk%57Mk-?dPfq{#GiGiDen?ZnqXL1ln6aa1kSRViY delta 291 zcmca0v_^2k3C5VoKFs!$IT(f6d{c{y6VoRfGpcj2=YrX(n-dsg7^P)=5=-<`^0TuO zQ}r|Qb5jcv(^K^!syDx6>SktSnOw@|$S5*-J6kWK#N_R4ij&jW1M3-fGcYqSGB7aA z-_0Nq$+(?CV>5%8kk)1fJprjbT;5vD%>G&|%>G)e%>G(zto~Z;to~XYto~X8AdUct zC&0nsuO+|VH;CX7VDr}!;02R>V3J<|BrX6Z1;M0{0GGd=mVmGTm%o;P2$&QF unJfk(#6g4vh>&FU*V@crw2^^\n ") - jteOutput.setContext("strong", null) - jteOutput.writeUserContent(message.author) - jteOutput.writeContent(":\n ") + @JvmField val JTE_LINE_INFO = intArrayOf(0,0,0,1,2,3,4,6,6,6,6,6,8,8,8,9,9,10,10,14,15,15,15,15,18,21,21,21,24,24,24,24,24,24,28,30,30,30,34,34,34,6,6,6,6,6) + @JvmStatic fun render(jteOutput:gg.jte.html.HtmlTemplateOutput, jteHtmlInterceptor:gg.jte.html.HtmlInterceptor?, model:MessageTemplate) { + jteOutput.writeContent("\n") + val dateFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy").withZone(ZoneId.systemDefault()) + jteOutput.writeContent("\n") + val timeFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm").withZone(ZoneId.systemDefault()) + jteOutput.writeContent("\n") + val borderColors = listOf("blue", "green", "pink", "orange") + jteOutput.writeContent("\n\n
\n
\n ") + jteOutput.writeContent("\n
\n (") + jteOutput.writeContent("\">
\n\n
\n ") + jteOutput.writeContent("\n
\n \n ") jteOutput.setContext("span", null) - jteOutput.writeUserContent(message.createdAt.toString()) - jteOutput.writeContent(")\n \n
") + jteOutput.writeUserContent(model.message.author) + jteOutput.writeContent("\n \n \n ") + jteOutput.setContext("span", null) + jteOutput.writeUserContent(dateFormatter.format(model.message.createdAt)) + jteOutput.writeContent(" • ") + jteOutput.setContext("span", null) + jteOutput.writeUserContent(timeFormatter.format(model.message.createdAt)) + jteOutput.writeContent("\n \n
\n\n ") + jteOutput.writeContent("\n
\n ") + jteOutput.setContext("div", null) + jteOutput.writeUserContent(model.message.content) + jteOutput.writeContent("\n
\n
\n
\n") } @JvmStatic fun renderMap(jteOutput:gg.jte.html.HtmlTemplateOutput, jteHtmlInterceptor:gg.jte.html.HtmlInterceptor?, params:Map) { - val message = params["message"] as Message - render(jteOutput, jteHtmlInterceptor, message); + val model = params["model"] as MessageTemplate + render(jteOutput, jteHtmlInterceptor, model); } } } diff --git a/jte-classes/META-INF/main.kotlin_module b/jte-classes/META-INF/main.kotlin_module new file mode 100644 index 0000000000000000000000000000000000000000..9dbc290d21e8fd8815939343a7a5484dc57cfcde GIT binary patch literal 24 ZcmZQzU|?ooU|?ckU|?i`0wo451^@wK08;<} literal 0 HcmV?d00001 diff --git a/jte-classes/gg/jte/generated/ondemand/JteIndexGenerated.kt b/jte-classes/gg/jte/generated/ondemand/JteIndexGenerated.kt new file mode 100644 index 0000000..a762a23 --- /dev/null +++ b/jte-classes/gg/jte/generated/ondemand/JteIndexGenerated.kt @@ -0,0 +1,35 @@ +@file:Suppress("ktlint") +package gg.jte.generated.ondemand +import at.dokkae.homepage.templates.IndexTemplate +import at.dokkae.homepage.templates.MessageTemplate +import gg.jte.support.ForSupport +@Suppress("UNCHECKED_CAST", "UNUSED_PARAMETER") +class JteIndexGenerated { +companion object { + @JvmField val JTE_NAME = "Index.kte" + @JvmField val JTE_LINE_INFO = intArrayOf(0,0,0,1,2,4,4,4,4,4,18,18,37,58,88,93,96,96,97,97,98,98,102,108,119,132,146,161,161,161,4,4,4,4,4) + @JvmStatic fun render(jteOutput:gg.jte.html.HtmlTemplateOutput, jteHtmlInterceptor:gg.jte.html.HtmlInterceptor?, model:IndexTemplate) { + jteOutput.writeContent("\n\n\n\n \n \n Dokkae's Chat\n\n \n \n \n\n \n\n\n
\n ") + jteOutput.writeContent("\n
\n

Dokkae's Chat

\n
\n\n ") + jteOutput.writeContent("\n
\n
\n ") + for (message in model.messages) { + jteOutput.writeContent("\n ") + gg.jte.generated.ondemand.partials.JteMessageGenerated.render(jteOutput, jteHtmlInterceptor, MessageTemplate(message)); + jteOutput.writeContent("\n ") + } + jteOutput.writeContent("\n
\n
\n\n ") + jteOutput.writeContent("\n
\n
\n ") + jteOutput.writeContent("\n
\n
\n \n
\n
\n\n ") + jteOutput.writeContent("\n
\n
\n
\n \n
\n\n ") + jteOutput.writeContent("\n \n
\n
\n
\n
\n\n ") + jteOutput.writeContent("\n \n
\n\n\n") + } + @JvmStatic fun renderMap(jteOutput:gg.jte.html.HtmlTemplateOutput, jteHtmlInterceptor:gg.jte.html.HtmlInterceptor?, params:Map) { + val model = params["model"] as IndexTemplate + render(jteOutput, jteHtmlInterceptor, model); + } +} +} diff --git a/jte-classes/gg/jte/generated/ondemand/partials/JteMessageGenerated.kt b/jte-classes/gg/jte/generated/ondemand/partials/JteMessageGenerated.kt new file mode 100644 index 0000000..06f028d --- /dev/null +++ b/jte-classes/gg/jte/generated/ondemand/partials/JteMessageGenerated.kt @@ -0,0 +1,46 @@ +@file:Suppress("ktlint") +package gg.jte.generated.ondemand.partials +import at.dokkae.homepage.templates.MessageTemplate +import java.time.Instant +import java.time.ZoneId +import java.time.format.DateTimeFormatter +import kotlin.math.absoluteValue +@Suppress("UNCHECKED_CAST", "UNUSED_PARAMETER") +class JteMessageGenerated { +companion object { + @JvmField val JTE_NAME = "partials/Message.kte" + @JvmField val JTE_LINE_INFO = intArrayOf(0,0,0,1,2,3,4,6,6,6,6,6,8,8,8,9,9,10,10,14,15,15,15,15,18,21,21,21,24,24,24,24,24,24,28,30,30,30,34,34,34,6,6,6,6,6) + @JvmStatic fun render(jteOutput:gg.jte.html.HtmlTemplateOutput, jteHtmlInterceptor:gg.jte.html.HtmlInterceptor?, model:MessageTemplate) { + jteOutput.writeContent("\n") + val dateFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy").withZone(ZoneId.systemDefault()) + jteOutput.writeContent("\n") + val timeFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm").withZone(ZoneId.systemDefault()) + jteOutput.writeContent("\n") + val borderColors = listOf("red", "orange", "yellow", "green", "blue", "pink" ) + jteOutput.writeContent("\n\n
\n
\n ") + jteOutput.writeContent("\n
\n\n
\n ") + jteOutput.writeContent("\n
\n \n ") + jteOutput.setContext("span", null) + jteOutput.writeUserContent(model.message.author) + jteOutput.writeContent("\n \n \n ") + jteOutput.setContext("span", null) + jteOutput.writeUserContent(dateFormatter.format(model.message.createdAt)) + jteOutput.writeContent(" • ") + jteOutput.setContext("span", null) + jteOutput.writeUserContent(timeFormatter.format(model.message.createdAt)) + jteOutput.writeContent("\n \n
\n\n ") + jteOutput.writeContent("\n
\n ") + jteOutput.setContext("div", null) + jteOutput.writeUserContent(model.message.content) + jteOutput.writeContent("\n
\n
\n
\n
") + } + @JvmStatic fun renderMap(jteOutput:gg.jte.html.HtmlTemplateOutput, jteHtmlInterceptor:gg.jte.html.HtmlInterceptor?, params:Map) { + val model = params["model"] as MessageTemplate + render(jteOutput, jteHtmlInterceptor, model); + } +} +} diff --git a/src/main/kotlin/at/dokkae/homepage/Homepage.kt b/src/main/kotlin/at/dokkae/homepage/Homepage.kt index 3f910d9..636ad47 100644 --- a/src/main/kotlin/at/dokkae/homepage/Homepage.kt +++ b/src/main/kotlin/at/dokkae/homepage/Homepage.kt @@ -1,10 +1,12 @@ package at.dokkae.homepage +import at.dokkae.homepage.config.Env import at.dokkae.homepage.config.Environment import at.dokkae.homepage.extensions.Precompiled import at.dokkae.homepage.repository.MessageRepository import at.dokkae.homepage.repository.impls.JooqMessageRepository -import at.dokkae.homepage.templates.Index +import at.dokkae.homepage.templates.IndexTemplate +import at.dokkae.homepage.templates.MessageTemplate import io.github.cdimascio.dotenv.dotenv import org.flywaydb.core.Flyway import org.http4k.core.HttpHandler @@ -14,18 +16,19 @@ import org.http4k.core.Status import org.http4k.core.body.form import org.http4k.core.getFirst import org.http4k.core.toParametersMap +import org.http4k.routing.ResourceLoader import org.http4k.routing.bindHttp import org.http4k.routing.bindSse import org.http4k.routing.poly import org.http4k.routing.routes import org.http4k.routing.sse +import org.http4k.routing.static import org.http4k.server.Jetty import org.http4k.server.asServer import org.http4k.sse.Sse import org.http4k.sse.SseMessage import org.http4k.sse.SseResponse import org.http4k.template.JTETemplates -import org.http4k.template.ViewModel import org.jooq.SQLDialect import org.jooq.impl.DSL import java.sql.DriverManager @@ -52,14 +55,11 @@ data class Message( val id: UUID = UUID.randomUUID(), val createdAt: Instant = Instant.now(), val updatedAt: Instant? = null -) : ViewModel { +) { init { require(author.length <= 31) { "Author must be 31 characters or less" } require(content.length <= 255) { "Content must be 255 characters or less" } } - - - override fun template(): String = "partials/Message" } fun main() { @@ -77,10 +77,19 @@ fun main() { val messageRepository: MessageRepository = JooqMessageRepository(dslContext) val subscribers = CopyOnWriteArrayList() - val renderer = JTETemplates().Precompiled("build/generated-resources/jte") + val renderer = when (env.appEnv) { + Env.DEVELOPMENT -> { + println("🔥 Hot-Reloading JTE templates") + JTETemplates().HotReload("src/main/kte") + } + Env.PRODUCTION -> { + println("📦 Loading pre-compiled JTE templates") + JTETemplates().Precompiled("build/generated-resources/jte") + } + } val indexHandler: HttpHandler = { - Response(Status.OK).body(renderer(Index(messageRepository.findAll()))) + Response(Status.OK).body(renderer(IndexTemplate(messageRepository.findAll()))) } val sse = sse( @@ -94,30 +103,38 @@ fun main() { ) val http = routes( + static(ResourceLoader.Classpath("static")), + "/" bindHttp GET to indexHandler, "/messages" bindHttp POST to { req -> - val params = req.form().toParametersMap() - val author = params.getFirst("author").takeIf { !it.isNullOrBlank() } ?: "Anonymous" - val message = params.getFirst("message") + try { + val params = req.form().toParametersMap() + val author = params.getFirst("author").takeIf { !it.isNullOrBlank() } ?: "Anonymous" + val message = params.getFirst("message") - if (message == null) { - Response(Status.BAD_REQUEST) - } else { - val msg = Message(author, message) - val sseMsg = SseMessage.Data(renderer(msg)) + if (message == null) { + Response(Status.BAD_REQUEST) + } else { + val msg = Message(author, message) + val sseMsg = SseMessage.Data(renderer(MessageTemplate(msg))) - messageRepository.save(msg) - subscribers.forEach { - thread { it.send(sseMsg) } + messageRepository.save(msg) + subscribers.forEach { + thread { it.send(sseMsg) } + } + + Response(Status.CREATED) } + } catch (ex: Exception) { + println("Failed to receive message: ${ex.toString()} ${ex.message}") - Response(Status.CREATED) + Response(Status.INTERNAL_SERVER_ERROR) } } ) - poly(http, sse).asServer(Jetty(port = env.port)).start() + poly(http, sse).asServer(Jetty(port = env.appPort)).start() - println("Server started on http://${env.host}:${env.port}") + println("Server started on http://${env.appDomain}:${env.appPort}") } diff --git a/src/main/kotlin/at/dokkae/homepage/config/Environment.kt b/src/main/kotlin/at/dokkae/homepage/config/Environment.kt index 6321095..528c86e 100644 --- a/src/main/kotlin/at/dokkae/homepage/config/Environment.kt +++ b/src/main/kotlin/at/dokkae/homepage/config/Environment.kt @@ -2,9 +2,15 @@ package at.dokkae.homepage.config import io.github.cdimascio.dotenv.Dotenv +enum class Env { + DEVELOPMENT, + PRODUCTION, +} + data class Environment( - val port: Int, - val host: String, + val appPort: Int, + val appDomain: String, + val appEnv: Env, val dbUrl: String, val dbUsername: String, val dbPassword: String, @@ -16,8 +22,9 @@ data class Environment( * @throws IllegalStateException if required environment variables were not found within the provided `dotenv` instance. */ fun load(dotenv: Dotenv): Environment = Environment( - port = requireEnv(dotenv, "PORT").toInt(), - host = requireEnv(dotenv, "HOST"), + appPort = requireEnv(dotenv, "APP_PORT").toInt(), + appDomain = requireEnv(dotenv, "APP_DOMAIN"), + appEnv = Env.valueOf(requireEnv(dotenv, "APP_ENV").uppercase()), dbUrl = requireEnv(dotenv, "DB_URL"), dbUsername = requireEnv(dotenv, "DB_USERNAME"), dbPassword = requireEnv(dotenv, "DB_PASSWORD"), diff --git a/src/main/kotlin/at/dokkae/homepage/templates/Index.kt b/src/main/kotlin/at/dokkae/homepage/templates/Index.kt index 1258984..1e75cb7 100644 --- a/src/main/kotlin/at/dokkae/homepage/templates/Index.kt +++ b/src/main/kotlin/at/dokkae/homepage/templates/Index.kt @@ -3,6 +3,6 @@ package at.dokkae.homepage.templates import at.dokkae.homepage.Message import org.http4k.template.ViewModel -data class Index(val messages: List = listOf()) : ViewModel { +data class IndexTemplate(val messages: List = listOf()) : ViewModel { override fun template(): String = "Index" } \ No newline at end of file diff --git a/src/main/kotlin/at/dokkae/homepage/templates/Message.kt b/src/main/kotlin/at/dokkae/homepage/templates/Message.kt new file mode 100644 index 0000000..1b9eb18 --- /dev/null +++ b/src/main/kotlin/at/dokkae/homepage/templates/Message.kt @@ -0,0 +1,8 @@ +package at.dokkae.homepage.templates + +import at.dokkae.homepage.Message +import org.http4k.template.ViewModel + +data class MessageTemplate(val message: Message) : ViewModel { + override fun template(): String = "partials/Message" +} \ No newline at end of file diff --git a/src/main/kte/Index.kte b/src/main/kte/Index.kte index 08857e8..7b7933e 100644 --- a/src/main/kte/Index.kte +++ b/src/main/kte/Index.kte @@ -1,159 +1,162 @@ -@import at.dokkae.homepage.templates.Index +@import at.dokkae.homepage.templates.IndexTemplate +@import at.dokkae.homepage.templates.MessageTemplate +@import gg.jte.support.ForSupport -@param model: Index +@param model: IndexTemplate - Simple Chat — http4k + JTE + htmx + Dokkae's Chat + - -
-

Simple Chat

+ +
+ +
+

Dokkae's Chat

+
-
- @for (message in model.messages.reversed()) - @template.partials.Message(message) - @endfor + +
+
+ @for (message in model.messages) + @template.partials.Message(MessageTemplate(message)) + @endfor +
+ +
+
+ +
+
+ +
+
- - - - + +
+
+
+ +
+ + + +
+
+
-

No auth — anyone can post. Messages are stored only in memory.

+ +
+ \ No newline at end of file diff --git a/src/main/kte/partials/Message.kte b/src/main/kte/partials/Message.kte index 91f406f..4e43280 100644 --- a/src/main/kte/partials/Message.kte +++ b/src/main/kte/partials/Message.kte @@ -1,11 +1,35 @@ -@import at.dokkae.homepage.Message +@import at.dokkae.homepage.templates.MessageTemplate +@import java.time.Instant +@import java.time.ZoneId +@import java.time.format.DateTimeFormatter +@import kotlin.math.absoluteValue -@param message: Message +@param model: MessageTemplate -
- ${message.author}: - ${message.content} - - (${message.createdAt.toString()}) - +!{val dateFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy").withZone(ZoneId.systemDefault())} +!{val timeFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm").withZone(ZoneId.systemDefault())} +!{val borderColors = listOf("red", "orange", "yellow", "green", "blue", "pink" )} + +
+
+ +
+ +
+ +
+ + ${model.message.author} + + + ${dateFormatter.format(model.message.createdAt)} • ${timeFormatter.format(model.message.createdAt)} + +
+ + +
+ ${model.message.content} +
+
+
\ No newline at end of file diff --git a/src/main/resources/static/css/.keep b/src/main/resources/static/css/.keep new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/static/css/index.css b/src/main/resources/static/css/index.css new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/static/images/.keep b/src/main/resources/static/images/.keep new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/static/js/.keep b/src/main/resources/static/js/.keep new file mode 100644 index 0000000..e69de29 From a80473fb357cddec86b224502215cd84613efa31 Mon Sep 17 00:00:00 2001 From: Dokkae6949 Date: Sun, 14 Dec 2025 03:48:09 +0100 Subject: [PATCH 10/10] fix: forgot to run codegen on jte --- .../JteIndexGenerated$Companion.class | Bin 9727 -> 9947 bytes .../precompiled/JteIndexGenerated.class | Bin 2253 -> 2254 bytes .../precompiled/JteIndexGenerated.kt | 22 +++++++++--------- .../JteMessageGenerated$Companion.class | Bin 5186 -> 5220 bytes .../partials/JteMessageGenerated.kt | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated$Companion.class b/build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated$Companion.class index 692b37c5c7342e2f136008629efe4420c086e7c5..448574bee4a2ab000f00a5d9b1766319b926f593 100644 GIT binary patch delta 1629 zcmezGecPAo)W2Q(7#J8#80Ku`y3fYAeex@|Vn(CMaqM&X^fF3vD|8c6Qc_bCs<|f1 zvnx!#$;LhT6}!S@ZFbJdbJ+POb8%QPKApUfLz1~DHD&S!Hp$7=9Gt9aX-UROlNWGG zO#a6qIk}iqlO-)B4KBb|nVOT6Uyh_Y4Iw#s7l%4qQes+KvgPE3oZ?^u;yBdUk`hx5 z)6$?q4y-9DX(?bHBiH2ZoO>A;PcG%E<#5T*&Q45KFP{8^OPPs>Yw~+;(aE{oQle=& zsTB$!LN_@-N4F@oEVZaOb#fcG^W+$AK{+LbOi%ZxUj3)>3s&SYym~k_hFqluS=M|T>WMp8^NG$eCtteq+VAjx#;$g66 zu;FH~Vz8aOkynAkp1}dcah!aUS61W@iYR9K&BK6T-z1 z%n-`Rz>8u92SYd`gTmxMX))fE%rZMJup|dV6SuNPEcVu@vB zItJoRUN6Wt`IE4`Fd}@4^2-&{6AN^WCw~-_n0!xAm{DQ!8)3=G4I&(q4Ma>Q3-GZ_ zwi8kZ(>)?uV7gC;ck*Eo9WeX7hzgh%7S)^FAjUoUoX`z0UqOt0@&RGq$-I1AtnrMj ztz45C`9vm1iD`jN-YdgCxmzrA@;@;XFyBbL0!*(Gw*}FgpNm^EgBX()q(#BBskHE9 zUOtY=9@0XSUvqO#mJ;BbtS`nrSwTQ_a=J7xW8&sg=^u=Y$(!?JYZ*my85wvHaqOE| zz|N3A`M;bYMH%)gGqpafnhoW1A{O#10#bV0|NsigAl`HKNXJp z84L^zyvz)|3=9l>3=9nX;Lyur$Yx*#g&so_0}I$X4Q(Oe9SoAXLU~|PY9~Vp6GNm> z*$#%v0}OgrELz$+k}TU8szKg`#10<=GXoEUJcB%g0)sk(BHR=544e!g$FVRlFlaDX zLLv;rg!w`P?h6fuT!tD3W`>#ID9=Il&15?j33S)zGB5}*GO#k#GBAQ&ugky)4h~Sl zsRKEU5$p^xh#))!SsCgX8WFgLlmN?9Q81FO-#7mZ+bTn3t~aS&~|mn3R*s&S1>Qppczkl9QRIpPZkQlbT$TnV(mz z?~Gu3m#{OKGBR*LtxRELP}A_iG|E~NB3N3InWOKMSzKbx!(h%}!Np+4V9Ch9mzBt0 zmZ%SxWM{CRyqj0e%9g>7o56;`o{<6KIq_#A*clud8Q3!ti~Uk7N*EcKH8i7m z7@QegxEY)nTqjHODR8?pcz`&bj0{qf{rIKW*%`bU86>$T9~6;b<6!V*WU!nZrzAUh z7M~oW|Ky!~VcdZXL7WT$48e>HI+Fx+nAsUZCwua%afWj-gfT=gGB`t(%kZi==jRqA z=4IyRu`@(X-p60c6~o04%@E7TAj&nlQAmWFgCU-g!HY{lK|x`%qKx!pO&JB=l*}?a zF0c>>L*nKlfdEFGN`qAHX33Gq&L5Y?GnAgVHXhN#};`LgVr{|PZNvZgb#s&Y-fA!Y^=nk*}x$(fsC z1xgjVhLc;xO(!1`ubAv4VY|6q!jgIN32D*EPo;%9ZS<2$OG@(d>?ZpQh)wpC;bqL+ z94_;NkuiI7fLtx3NGT%&Zx$$7fCJt)v4EYSeDXtiLyk&@DsF}fhU&>u3Lz@Bj0`-< z8L7$He)%PSr8zk~4D}4+TnwTN4Ll6o3_M&6Obkt%Cn@}4WSl;^U+IO)ECvP!eFjDb zMg|53R;}#}92*%J7?>DlGcYi)fdx4j=1iWgEXg~Ifq^lSfsKKUfq`MiSC zb}(4&WN=_)uws#9*~#F>$S{+^7{u~oWH`X!W5ud1X0?Oq# NW+*CVC@p4~0syANTDSlJ diff --git a/build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated.class b/build/generated-resources/jte/gg/jte/generated/precompiled/JteIndexGenerated.class index d3e2cd6757bf082345b66256ed0f1d0f48e0cf1b..4c47fad7448317a0fb38bd9a3d42492b71136145 100644 GIT binary patch delta 128 zcmX>rcusIbH9O}I24)6E1_p*ZlUvxs)2#fp1o#9Z{Ivx51!DcR1Ox;U{IvuG!K9Et zqQ91aFqjk(Nb=Vb5CxNB0%`tQ0^$NW{#pVO0_FZ%0+NCZE&f^pQi2SV{Ivw61sN9l RYYE6eC|N;ncvf&jH9O~b24)6E1_p-PlUvxsQ%(J~1o#9z{j~)61^oQA1Ox\n\n\n \n \n Dokkae's Chat\n\n \n \n \n\n \n\n\n
\n ") - jteOutput.writeContent("\n
\n

Simple Chat

\n
\n\n ") - jteOutput.writeContent("\n
\n
\n
\n
\n ") - for (message in model.messages.reversed()) { - jteOutput.writeContent("\n ") + jteOutput.writeContent("\n @keyframes slideIn {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n\n .animate-slide-in.htmx-added {\n opacity: 0;\n }\n\n .animate-slide-in {\n opacity: 1;\n animation: slideIn 0.3s ease-out;\n }\n\n ") + jteOutput.writeContent("\n .message-border-red {\n background-color: #ffb3ba !important;\n }\n\n .message-border-orange {\n background-color: #ffdfba !important;\n }\n\n .message-border-yellow {\n background-color: #ffffba !important;\n }\n\n .message-border-green {\n background-color: #baffc9 !important;\n }\n\n .message-border-blue {\n background-color: #bae1ff !important;\n }\n\n .message-border-pink {\n background-color: #fddfdf !important;\n }\n\n\n \n\n\n
\n ") + jteOutput.writeContent("\n
\n

Dokkae's Chat

\n
\n\n ") + jteOutput.writeContent("\n
\n
\n ") + for (message in model.messages) { + jteOutput.writeContent("\n ") gg.jte.generated.precompiled.partials.JteMessageGenerated.render(jteOutput, jteHtmlInterceptor, MessageTemplate(message)); - jteOutput.writeContent("\n ") + jteOutput.writeContent("\n ") } - jteOutput.writeContent("\n
\n
\n
\n
\n\n ") + jteOutput.writeContent("\n
\n
\n\n ") jteOutput.writeContent("\n
\n
\n ") jteOutput.writeContent("\n
\n
\n \n
\n
\n\n ") - jteOutput.writeContent("\n
\n
\n \n
\n
\n\n ") - jteOutput.writeContent("\n \n
\n
\n\n ") + jteOutput.writeContent("\n
\n
\n
\n \n
\n\n ") + jteOutput.writeContent("\n \n
\n
\n
\n \n\n ") jteOutput.writeContent("\n \n
\n\n\n") } @JvmStatic fun renderMap(jteOutput:gg.jte.html.HtmlTemplateOutput, jteHtmlInterceptor:gg.jte.html.HtmlInterceptor?, params:Map) { diff --git a/build/generated-resources/jte/gg/jte/generated/precompiled/partials/JteMessageGenerated$Companion.class b/build/generated-resources/jte/gg/jte/generated/precompiled/partials/JteMessageGenerated$Companion.class index e642725ebfd0236cab4307a4386590f18040d638..356b8f657cff5bab3e447b0bd6e1a3312ebba154 100644 GIT binary patch delta 1574 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 PONtqm7Bj3UW;g}_VXZxU diff --git a/build/generated-resources/jte/gg/jte/generated/precompiled/partials/JteMessageGenerated.kt b/build/generated-resources/jte/gg/jte/generated/precompiled/partials/JteMessageGenerated.kt index 8d78ca6..f00a90c 100644 --- a/build/generated-resources/jte/gg/jte/generated/precompiled/partials/JteMessageGenerated.kt +++ b/build/generated-resources/jte/gg/jte/generated/precompiled/partials/JteMessageGenerated.kt @@ -16,7 +16,7 @@ companion object { jteOutput.writeContent("\n") val timeFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm").withZone(ZoneId.systemDefault()) jteOutput.writeContent("\n") - val borderColors = listOf("blue", "green", "pink", "orange") + val borderColors = listOf("red", "orange", "yellow", "green", "blue", "pink" ) jteOutput.writeContent("\n\n
\n
\n ") jteOutput.writeContent("\n