diff --git a/build.gradle b/build.gradle index cd73bde..181d9db 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'org.example' -version '0.1.1' +version '0.2.0' repositories { mavenCentral() @@ -24,7 +24,7 @@ dependencies { // See https://github.com/JetBrains/gradle-intellij-plugin/ intellij { version '2020.2.1' - plugins = ['gradle'] + plugins = ['gradle', 'java', 'org.jetbrains.kotlin'] } patchPluginXml { changeNotes """ diff --git a/src/main/kotlin/tech/stonks/kvizard/KVisionModuleBuilder.kt b/src/main/kotlin/tech/stonks/kvizard/KVisionModuleBuilder.kt index 9d5f718..e739819 100644 --- a/src/main/kotlin/tech/stonks/kvizard/KVisionModuleBuilder.kt +++ b/src/main/kotlin/tech/stonks/kvizard/KVisionModuleBuilder.kt @@ -1,6 +1,6 @@ package tech.stonks.kvizard -import com.intellij.execution.executors.DefaultRunExecutor +import com.intellij.ide.fileTemplates.FileTemplateManager import com.intellij.ide.util.projectWizard.ModuleBuilder import com.intellij.ide.util.projectWizard.ModuleWizardStep import com.intellij.ide.util.projectWizard.WizardContext @@ -14,13 +14,12 @@ import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiManager import com.intellij.psi.impl.file.PsiDirectoryFactory -import org.jetbrains.plugins.gradle.action.GradleExecuteTaskAction import tech.stonks.kvizard.generator.FrontendTreeGenerator import tech.stonks.kvizard.generator.KtorTreeGenerator +import tech.stonks.kvizard.generator.SpringTreeGenerator import tech.stonks.kvizard.generator.TreeGenerator import tech.stonks.kvizard.step.library_choice.LibraryChoiceStep -import tech.stonks.kvizard.utils.backgroundTask -import tech.stonks.kvizard.utils.runGradle +import tech.stonks.kvizard.utils.* import java.io.File class KVisionModuleBuilder : ModuleBuilder() { @@ -30,8 +29,9 @@ class KVisionModuleBuilder : ModuleBuilder() { * Here add libraries that were newly supported */ val supportedBackendLibraries = arrayOf( - KVisionBackendLibrary.KTOR, - KVisionBackendLibrary.FRONTEND_ONLY + KVisionBackendLibrary.KTOR, + KVisionBackendLibrary.SPRING_BOOT, + KVisionBackendLibrary.FRONTEND_ONLY ) } @@ -46,8 +46,8 @@ class KVisionModuleBuilder : ModuleBuilder() { ApplicationManager.getApplication().runWriteAction { val manager = PsiManager.getInstance(modifiableRootModel.project) manager.findFile(root)?.add( - PsiDirectoryFactory.getInstance(manager.project) - .createDirectory(root.createChildDirectory(null, "webpack")) + PsiDirectoryFactory.getInstance(manager.project) + .createDirectory(root.createChildDirectory(null, "webpack")) ) } } catch (ex: java.lang.Exception) { @@ -61,6 +61,8 @@ class KVisionModuleBuilder : ModuleBuilder() { } runGradleTasks(modifiableRootModel.project) + RunConfigurationUtil.createConfiguration(modifiableRootModel.project) + KVisionDialogUtil.showNewsDialog() } } @@ -72,6 +74,7 @@ class KVisionModuleBuilder : ModuleBuilder() { return when (backendLibrary) { KVisionBackendLibrary.KTOR -> KtorTreeGenerator() KVisionBackendLibrary.FRONTEND_ONLY -> FrontendTreeGenerator() + KVisionBackendLibrary.SPRING_BOOT -> SpringTreeGenerator() else -> throw IllegalStateException("${backendLibrary.name} is not supported yet.") } } @@ -88,4 +91,6 @@ class KVisionModuleBuilder : ModuleBuilder() { override fun getCustomOptionsStep(context: WizardContext?, parentDisposable: Disposable?): ModuleWizardStep? { return LibraryChoiceStep(this) } + + } \ No newline at end of file diff --git a/src/main/kotlin/tech/stonks/kvizard/action/StartupAction.kt b/src/main/kotlin/tech/stonks/kvizard/action/StartupAction.kt new file mode 100644 index 0000000..95ce9e2 --- /dev/null +++ b/src/main/kotlin/tech/stonks/kvizard/action/StartupAction.kt @@ -0,0 +1,11 @@ +package tech.stonks.kvizard.action + +import com.intellij.openapi.components.ProjectComponent +import tech.stonks.kvizard.utils.KVisionDialogUtil + +@Suppress("DEPRECATION") +class StartupAction : ProjectComponent { + override fun initComponent() { + KVisionDialogUtil.showNewsDialog() + } +} \ No newline at end of file diff --git a/src/main/kotlin/tech/stonks/kvizard/action/notification.kt b/src/main/kotlin/tech/stonks/kvizard/action/notification.kt new file mode 100644 index 0000000..d9abca7 --- /dev/null +++ b/src/main/kotlin/tech/stonks/kvizard/action/notification.kt @@ -0,0 +1,25 @@ +package tech.stonks.kvizard.action + +import com.intellij.ide.BrowserUtil +import com.intellij.notification.Notification +import com.intellij.notification.NotificationAction +import com.intellij.openapi.actionSystem.AnActionEvent +import tech.stonks.kvizard.settings.AppSettingsState + +class NewsAction(text: String) : NotificationAction(text) { + override fun actionPerformed(e: AnActionEvent, notification: Notification) { + BrowserUtil.browse("https://kotlin.news") + notification.expire() + val appSettings = AppSettingsState.getInstance() + appSettings?.state?.isNotificationDisabled = true + } +} + +class NotShowAction(text: String) : NotificationAction(text) { + override fun actionPerformed(e: AnActionEvent, notification: Notification) { + notification.expire() + val appSettings = AppSettingsState.getInstance() + appSettings?.state?.isNotificationDisabled = true + + } +} \ No newline at end of file diff --git a/src/main/kotlin/tech/stonks/kvizard/data/VersionApi.kt b/src/main/kotlin/tech/stonks/kvizard/data/VersionApi.kt index 70f3f8f..9160fdb 100644 --- a/src/main/kotlin/tech/stonks/kvizard/data/VersionApi.kt +++ b/src/main/kotlin/tech/stonks/kvizard/data/VersionApi.kt @@ -13,13 +13,13 @@ interface VersionApi { fun getVersionData(): Single companion object { - fun create() : VersionApi { + fun create(): VersionApi { return Retrofit.Builder() - .baseUrl("https://raw.githubusercontent.com/rjaros/kvision/master/") - .addConverterFactory(GsonConverterFactory.create()) - .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) - .build() - .create(VersionApi::class.java) + .baseUrl("https://raw.githubusercontent.com/rjaros/kvision/master/") + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) + .build() + .create(VersionApi::class.java) } } } \ No newline at end of file diff --git a/src/main/kotlin/tech/stonks/kvizard/generator/SpringTreeGenerator.kt b/src/main/kotlin/tech/stonks/kvizard/generator/SpringTreeGenerator.kt new file mode 100644 index 0000000..176d928 --- /dev/null +++ b/src/main/kotlin/tech/stonks/kvizard/generator/SpringTreeGenerator.kt @@ -0,0 +1,8 @@ +package tech.stonks.kvizard.generator + +class SpringTreeGenerator : TreeGenerator( + "spring", + false, + backendFiles = arrayOf("Main.kt", "Service.kt"), + backendResourcesFiles = arrayOf("application.yml", "logback.xml") +) \ No newline at end of file diff --git a/src/main/kotlin/tech/stonks/kvizard/settings/AppSettingsState.kt b/src/main/kotlin/tech/stonks/kvizard/settings/AppSettingsState.kt new file mode 100644 index 0000000..8ab8ee2 --- /dev/null +++ b/src/main/kotlin/tech/stonks/kvizard/settings/AppSettingsState.kt @@ -0,0 +1,33 @@ +package tech.stonks.kvizard.settings + +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.components.* +import com.intellij.openapi.project.ProjectManager +import com.intellij.serviceContainer.ComponentManagerImpl + +@State( + name = "KVisionWizardSettings", + storages = [Storage("KVisionWizardSettings.xml", )] +) +class AppSettingsState : PersistentStateComponent { + data class State( + var lastDisplayed: Long = 0L, + var isNotificationDisabled: Boolean = false + ) + + companion object { + fun getInstance(): AppSettingsState? { + return ApplicationManager.getApplication().getComponent(AppSettingsState::class.java) + } + } + + private var _state: State = State() + + override fun getState(): State? { + return _state + } + + override fun loadState(state: State) { + _state = state + } +} \ No newline at end of file diff --git a/src/main/kotlin/tech/stonks/kvizard/step/library_choice/LibraryChoiceView.kt b/src/main/kotlin/tech/stonks/kvizard/step/library_choice/LibraryChoiceView.kt index f0bad43..bbf9ff4 100644 --- a/src/main/kotlin/tech/stonks/kvizard/step/library_choice/LibraryChoiceView.kt +++ b/src/main/kotlin/tech/stonks/kvizard/step/library_choice/LibraryChoiceView.kt @@ -1,9 +1,11 @@ package tech.stonks.kvizard.step.library_choice +import com.intellij.ide.BrowserUtil import com.intellij.openapi.ui.ComboBox import tech.stonks.kvizard.KVisionBackendLibrary import tech.stonks.kvizard.KVisionModuleBuilder import tech.stonks.kvizard.utils.setOnTextChangedListener +import java.awt.Color import java.awt.FlowLayout import javax.swing.* @@ -48,6 +50,13 @@ class LibraryChoiceView( onChanged() } }) + add(JButton("Check Kotlin.News").apply { + background = Color(0xffe017) + + this.addActionListener { + BrowserUtil.browse("https://kotlin.news") + } + }) } add(panel) } diff --git a/src/main/kotlin/tech/stonks/kvizard/utils/KVisionDialogUtil.kt b/src/main/kotlin/tech/stonks/kvizard/utils/KVisionDialogUtil.kt new file mode 100644 index 0000000..56f8085 --- /dev/null +++ b/src/main/kotlin/tech/stonks/kvizard/utils/KVisionDialogUtil.kt @@ -0,0 +1,35 @@ +package tech.stonks.kvizard.utils + +import com.intellij.notification.Notification +import com.intellij.notification.NotificationType +import com.intellij.notification.Notifications +import com.intellij.openapi.util.IconLoader +import tech.stonks.kvizard.action.NewsAction +import tech.stonks.kvizard.action.NotShowAction +import tech.stonks.kvizard.settings.AppSettingsState + +object KVisionDialogUtil { + fun showNewsDialog() { + val appSettings = AppSettingsState.getInstance() + if (appSettings?.state?.isNotificationDisabled == false && appSettings.state?.wasPublishedRecently() == false) { + + Notifications.Bus.notify( + Notification( + Notifications.SYSTEM_MESSAGES_GROUP_ID, + "Invitation", + "You have got invitation to join our community! Join Kotlin.News and become ninja developer in Kotlin.", + NotificationType.INFORMATION + ).apply { + icon = IconLoader.getIcon("/images/email-black-18dp.svg") + this.addAction(NewsAction("Join Kotlin.News")) + this.addAction(NotShowAction("Do not show again")) + } + ) + appSettings.state?.lastDisplayed = System.currentTimeMillis() + } + } + + private fun AppSettingsState.State.wasPublishedRecently(): Boolean { + return (System.currentTimeMillis() - this.lastDisplayed) < 1000 * 60 * 60 * 12 + } +} \ No newline at end of file diff --git a/src/main/kotlin/tech/stonks/kvizard/utils/RunConfigurationUtil.kt b/src/main/kotlin/tech/stonks/kvizard/utils/RunConfigurationUtil.kt new file mode 100644 index 0000000..820b0de --- /dev/null +++ b/src/main/kotlin/tech/stonks/kvizard/utils/RunConfigurationUtil.kt @@ -0,0 +1,61 @@ +package tech.stonks.kvizard.utils + +import com.intellij.execution.RunnerAndConfigurationSettings +import com.intellij.execution.configurations.ConfigurationFactory +import com.intellij.execution.configurations.RunConfiguration +import com.intellij.execution.impl.RunManagerImpl +import com.intellij.execution.impl.RunnerAndConfigurationSettingsImpl +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.IconLoader +import org.jetbrains.plugins.gradle.service.execution.GradleExternalTaskConfigurationType +import org.jetbrains.plugins.gradle.service.execution.GradleRunConfiguration +import javax.swing.Icon + +class KVisionConfigurationFactory(val task: String, private val args: String = "") : + ConfigurationFactory(GradleExternalTaskConfigurationType.getInstance()) { + override fun createTemplateConfiguration(project: Project): RunConfiguration { + val conf = GradleRunConfiguration( + project, + GradleExternalTaskConfigurationType.getInstance().factory, + "Run $task" + ) + conf.settings.externalProjectPath = project.basePath + conf.settings.taskNames = listOf(task) + conf.settings.scriptParameters = args + return conf + } + + override fun getName(): String = "Run $task" + + override fun getIcon(): Icon = IconLoader.getIcon("/images/logo16.png") +} + +class RunnerComparator : Comparator { + override fun compare(o1: RunnerAndConfigurationSettings?, o2: RunnerAndConfigurationSettings?): Int { + return when { + o1?.factory is KVisionConfigurationFactory -> 1 + o2?.factory is KVisionConfigurationFactory -> -1 + else -> 0 + } + } +} + +object RunConfigurationUtil { + fun createConfiguration(project: Project) { + val runManager = RunManagerImpl.getInstanceImpl(project) + runManager.addConfiguration( + RunnerAndConfigurationSettingsImpl( + RunManagerImpl.getInstanceImpl(project), + KVisionConfigurationFactory("backendRun").createTemplateConfiguration(project) + ) + ) + runManager.addConfiguration( + RunnerAndConfigurationSettingsImpl( + RunManagerImpl.getInstanceImpl(project), + KVisionConfigurationFactory("frontendRun", "-t").createTemplateConfiguration(project) + ) + ) + runManager.setOrder(RunnerComparator()) + runManager.requestSort() + } +} \ No newline at end of file diff --git a/src/main/kotlin/tech/stonks/kvizard/utils/file.kt b/src/main/kotlin/tech/stonks/kvizard/utils/file.kt index ae2bddb..bdcb761 100644 --- a/src/main/kotlin/tech/stonks/kvizard/utils/file.kt +++ b/src/main/kotlin/tech/stonks/kvizard/utils/file.kt @@ -2,6 +2,7 @@ package tech.stonks.kvizard.utils import com.intellij.execution.executors.DefaultRunExecutor import com.intellij.ide.fileTemplates.FileTemplateManager +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile import org.jetbrains.plugins.gradle.action.GradleExecuteTaskAction @@ -38,8 +39,8 @@ fun File.file(name: String, templateName: String, attributes: Map = emptyMap()): String { val template = FileTemplateManager - .getDefaultInstance() - .getInternalTemplate(templateName) + .getDefaultInstance() + .getInternalTemplate(templateName) return if (attributes.isEmpty()) { template.text } else { @@ -55,6 +56,20 @@ fun Project.getRootFile(): VirtualFile? { return projectFile?.parent?.parent } +fun String.insertAfter(after: Regex, insert: String): String { + val last = after.find(this)?.range?.last + return if(last != null) { + buildString { + append(this.substring(0, last+1)) + appendln(insert) + appendln(this.substring(last+1)) + } + }else { + this + } + +} + object TemplateAttributes { const val GROUP_ID = "GROUP_ID" const val ARTIFACT_ID = "ARTIFACT_ID" diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index fc7234b..904fd63 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -14,8 +14,14 @@ - - - - + + + tech.stonks.kvizard.settings.AppSettingsState + + + + + tech.stonks.kvizard.action.StartupAction + + \ No newline at end of file diff --git a/src/main/resources/fileTemplates/internal/runConfigurations.xml.ft b/src/main/resources/fileTemplates/internal/runConfigurations.xml.ft new file mode 100644 index 0000000..6e9f372 --- /dev/null +++ b/src/main/resources/fileTemplates/internal/runConfigurations.xml.ft @@ -0,0 +1,38 @@ + + + + + + true + + + + + + + + true + + \ No newline at end of file diff --git a/src/main/resources/fileTemplates/internal/spring_backend_resources_application.yml.ft b/src/main/resources/fileTemplates/internal/spring_backend_resources_application.yml.ft new file mode 100644 index 0000000..449f33a --- /dev/null +++ b/src/main/resources/fileTemplates/internal/spring_backend_resources_application.yml.ft @@ -0,0 +1,5 @@ +server: + compression: + enabled: true + mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json + min-response-size: 1024 \ No newline at end of file diff --git a/src/main/resources/fileTemplates/internal/spring_backend_resources_logback.xml.ft b/src/main/resources/fileTemplates/internal/spring_backend_resources_logback.xml.ft new file mode 100644 index 0000000..265820d --- /dev/null +++ b/src/main/resources/fileTemplates/internal/spring_backend_resources_logback.xml.ft @@ -0,0 +1,16 @@ + + + + + %d [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/fileTemplates/internal/spring_backend_source_Main.kt.ft b/src/main/resources/fileTemplates/internal/spring_backend_source_Main.kt.ft new file mode 100644 index 0000000..1464180 --- /dev/null +++ b/src/main/resources/fileTemplates/internal/spring_backend_source_Main.kt.ft @@ -0,0 +1,22 @@ +package ${PACKAGE_NAME} + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.runApplication +import org.springframework.context.annotation.Bean + +@SpringBootApplication +@EnableAutoConfiguration( + exclude = [ + org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration::class, + org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration::class + ] +) +class KVApplication { + @Bean + fun getManagers() = listOf(PingServiceManager) +} + +fun main(args: Array) { + runApplication(*args) +} \ No newline at end of file diff --git a/src/main/resources/fileTemplates/internal/spring_backend_source_Service.kt.ft b/src/main/resources/fileTemplates/internal/spring_backend_source_Service.kt.ft new file mode 100644 index 0000000..4b8527f --- /dev/null +++ b/src/main/resources/fileTemplates/internal/spring_backend_source_Service.kt.ft @@ -0,0 +1,15 @@ +package ${PACKAGE_NAME} + +import org.springframework.beans.factory.config.ConfigurableBeanFactory +import org.springframework.context.annotation.Scope +import org.springframework.stereotype.Service + +@Service +@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) +actual class PingService : IPingService { + + override suspend fun ping(message: String): String { + println(message) + return "Hello world from server!" + } +} \ No newline at end of file diff --git a/src/main/resources/fileTemplates/internal/spring_build.gradle.kts.ft b/src/main/resources/fileTemplates/internal/spring_build.gradle.kts.ft new file mode 100644 index 0000000..f4b0e7a --- /dev/null +++ b/src/main/resources/fileTemplates/internal/spring_build.gradle.kts.ft @@ -0,0 +1,248 @@ +import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpack +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig + +import org.springframework.boot.gradle.tasks.bundling.BootJar +import org.springframework.boot.gradle.tasks.run.BootRun + +plugins { + val kotlinVersion: String by System.getProperties() + id("kotlinx-serialization") version kotlinVersion + kotlin("multiplatform") version kotlinVersion + id("io.spring.dependency-management") version System.getProperty("dependencyManagementPluginVersion") + id("org.springframework.boot") version System.getProperty("springBootVersion") + kotlin("plugin.spring") version kotlinVersion + val kvisionVersion: String by System.getProperties() + id("kvision") version kvisionVersion +} + +extra["kotlin.version"] = "1.4.10" + +version = "1.0.0-SNAPSHOT" +group = "${GROUP_ID}" + +repositories { + mavenCentral() + jcenter() + maven { url = uri("https://dl.bintray.com/kotlin/kotlin-eap") } + maven { url = uri("https://kotlin.bintray.com/kotlinx") } + maven { url = uri("https://dl.bintray.com/kotlin/kotlin-js-wrappers") } + maven { url = uri("https://dl.bintray.com/rjaros/kotlin") } + maven { url = uri("https://repo.spring.io/milestone") } + maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") } + mavenLocal() +} + +// Versions +val kotlinVersion: String by System.getProperties() +val kvisionVersion: String by System.getProperties() +val coroutinesVersion: String by project +val springDataR2dbcVersion: String by project +val r2dbcPostgresqlVersion: String by project +val r2dbcH2Version: String by project +val kweryVersion: String by project + +val webDir = file("src/frontendMain/web") +val mainClassName = "${GROUP_ID}.${ARTIFACT_ID}.MainKt" + +kotlin { + jvm("backend") { + withJava() + compilations.all { + kotlinOptions { + jvmTarget = "1.8" + freeCompilerArgs = listOf("-Xjsr305=strict") + } + } + } + js("frontend") { + browser { + runTask { + outputFileName = "main.bundle.js" + sourceMaps = false + devServer = KotlinWebpackConfig.DevServer( + open = false, + port = 3000, + proxy = mapOf( + "/kv/*" to "http://localhost:8080", + "/kvws/*" to mapOf("target" to "ws://localhost:8080", "ws" to true) + ), + contentBase = listOf("$buildDir/processedResources/frontend/main") + ) + } + webpackTask { + outputFileName = "main.bundle.js" + } + testTask { + useKarma { + useChromeHeadless() + } + } + } + } + sourceSets { + val commonMain by getting { + dependencies { + api("pl.treksoft:kvision-server-spring-boot:$kvisionVersion") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion") + } + kotlin.srcDir("build/generated-src/common") + } + val commonTest by getting { + dependencies { + implementation(kotlin("test-common")) + implementation(kotlin("test-annotations-common")) + } + } + val backendMain by getting { + dependencies { + implementation(kotlin("stdlib-jdk8")) + implementation(kotlin("reflect")) + implementation("org.springframework.boot:spring-boot-starter") + implementation("org.springframework.boot:spring-boot-devtools") + implementation("org.springframework.boot:spring-boot-starter-webflux") + implementation("org.springframework.boot:spring-boot-starter-security") + implementation("org.springframework.data:spring-data-r2dbc:$springDataR2dbcVersion") + implementation("io.r2dbc:r2dbc-postgresql:$r2dbcPostgresqlVersion") + implementation("io.r2dbc:r2dbc-h2:$r2dbcH2Version") + implementation("com.github.andrewoma.kwery:core:$kweryVersion") + } + } + val backendTest by getting { + dependencies { + implementation(kotlin("test")) + implementation(kotlin("test-junit")) + implementation("org.springframework.boot:spring-boot-starter-test") + } + } + val frontendMain by getting { + resources.srcDir(webDir) + dependencies { + implementation("pl.treksoft:kvision:$kvisionVersion") + implementation("pl.treksoft:kvision-bootstrap:$kvisionVersion") + implementation("pl.treksoft:kvision-bootstrap-css:$kvisionVersion") + implementation("pl.treksoft:kvision-bootstrap-select:$kvisionVersion") + implementation("pl.treksoft:kvision-bootstrap-datetime:$kvisionVersion") + implementation("pl.treksoft:kvision-bootstrap-spinner:$kvisionVersion") + implementation("pl.treksoft:kvision-bootstrap-upload:$kvisionVersion") + implementation("pl.treksoft:kvision-bootstrap-dialog:$kvisionVersion") + implementation("pl.treksoft:kvision-fontawesome:$kvisionVersion") + implementation("pl.treksoft:kvision-i18n:$kvisionVersion") + implementation("pl.treksoft:kvision-richtext:$kvisionVersion") + implementation("pl.treksoft:kvision-handlebars:$kvisionVersion") + implementation("pl.treksoft:kvision-datacontainer:$kvisionVersion") + implementation("pl.treksoft:kvision-redux:$kvisionVersion") + implementation("pl.treksoft:kvision-chart:$kvisionVersion") + implementation("pl.treksoft:kvision-tabulator:$kvisionVersion") + implementation("pl.treksoft:kvision-pace:$kvisionVersion") + implementation("pl.treksoft:kvision-moment:$kvisionVersion") + } + kotlin.srcDir("build/generated-src/frontend") + } + val frontendTest by getting { + dependencies { + implementation(kotlin("test-js")) + implementation("pl.treksoft:kvision-testutils:$kvisionVersion:tests") + } + } + } +} + +fun getNodeJsBinaryExecutable(): String { + val nodeDir = NodeJsRootPlugin.apply(project).nodeJsSetupTaskProvider.get().destination + val isWindows = System.getProperty("os.name").toLowerCase().contains("windows") + val nodeBinDir = if (isWindows) nodeDir else nodeDir.resolve("bin") + val command = NodeJsRootPlugin.apply(project).nodeCommand + val finalCommand = if (isWindows && command == "node") "node.exe" else command + return nodeBinDir.resolve(finalCommand).absolutePath +} + +tasks { + create("generatePotFile", Exec::class) { + dependsOn("compileKotlinFrontend") + executable = getNodeJsBinaryExecutable() + args("$buildDir/js/node_modules/gettext-extract/bin/gettext-extract") + inputs.files(kotlin.sourceSets["frontendMain"].kotlin.files) + outputs.file("$projectDir/src/frontendMain/resources/i18n/messages.pot") + } +} +afterEvaluate { + tasks { + getByName("frontendProcessResources", Copy::class) { + dependsOn("compileKotlinFrontend") + exclude("**/*.pot") + doLast("Convert PO to JSON") { + destinationDir.walkTopDown().filter { + it.isFile && it.extension == "po" + }.forEach { + exec { + executable = getNodeJsBinaryExecutable() + args( + "$buildDir/js/node_modules/gettext.js/bin/po2json", + it.absolutePath, + "${it.parent}/${it.nameWithoutExtension}.json" + ) + println("Converted ${it.name} to ${it.nameWithoutExtension}.json") + } + it.delete() + } + } + } + create("frontendArchive", Jar::class).apply { + dependsOn("frontendBrowserProductionWebpack") + group = "package" + archiveAppendix.set("frontend") + val distribution = + project.tasks.getByName("frontendBrowserProductionWebpack", KotlinWebpack::class).destinationDirectory!! + from(distribution) { + include("*.*") + } + from(webDir) + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + into("/public") + inputs.files(distribution, webDir) + outputs.file(archiveFile) + manifest { + attributes( + mapOf( + "Implementation-Title" to rootProject.name, + "Implementation-Group" to rootProject.group, + "Implementation-Version" to rootProject.version, + "Timestamp" to System.currentTimeMillis() + ) + ) + } + } + getByName("backendProcessResources", Copy::class) { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + } + getByName("bootJar", BootJar::class) { + dependsOn("frontendArchive", "backendMainClasses") + classpath = files( + kotlin.targets["backend"].compilations["main"].output.allOutputs + + project.configurations["backendRuntimeClasspath"] + + (project.tasks["frontendArchive"] as Jar).archiveFile + ) + } + getByName("jar", Jar::class).apply { + dependsOn("bootJar") + } + getByName("bootRun", BootRun::class) { + dependsOn("backendMainClasses") + classpath = files( + kotlin.targets["backend"].compilations["main"].output.allOutputs + + project.configurations["backendRuntimeClasspath"] + ) + } + create("backendRun") { + dependsOn("bootRun") + group = "run" + } + getByName("compileKotlinBackend") { + dependsOn("compileKotlinMetadata") + } + getByName("compileKotlinFrontend") { + dependsOn("compileKotlinMetadata") + } + } +} \ No newline at end of file diff --git a/src/main/resources/fileTemplates/internal/spring_gradle.properties.ft b/src/main/resources/fileTemplates/internal/spring_gradle.properties.ft new file mode 100644 index 0000000..f7dccf9 --- /dev/null +++ b/src/main/resources/fileTemplates/internal/spring_gradle.properties.ft @@ -0,0 +1,15 @@ +javaVersion=1.8 +#Plugins +systemProp.kotlinVersion=${kotlin_version} +serializationVersion=${serialization_version} +systemProp.dependencyManagementPluginVersion=1.0.9.RELEASE +systemProp.springBootVersion=${spring_boot_version} +#Dependencies +systemProp.kvisionVersion=${kvision_version} +coroutinesVersion=${coroutines_version} +springDataR2dbcVersion=${spring_datar2dbc_version} +r2dbcPostgresqlVersion=${r2dbc_postgres_version} +r2dbcH2Version=${r2dbc_h2_version} +kweryVersion=0.17 + +kotlin.mpp.stability.nowarn=true \ No newline at end of file diff --git a/src/main/resources/fileTemplates/internal/spring_settings.gradle.kts.ft b/src/main/resources/fileTemplates/internal/spring_settings.gradle.kts.ft new file mode 100644 index 0000000..ac1e269 --- /dev/null +++ b/src/main/resources/fileTemplates/internal/spring_settings.gradle.kts.ft @@ -0,0 +1,23 @@ +pluginManagement { + repositories { + mavenCentral() + jcenter() + gradlePluginPortal() + maven { url = uri("https://plugins.gradle.org/m2/") } + maven { url = uri("https://dl.bintray.com/kotlin/kotlin-eap") } + maven { url = uri("https://kotlin.bintray.com/kotlinx") } + maven { url = uri("https://repo.spring.io/milestone") } + maven { url = uri("https://dl.bintray.com/rjaros/kotlin") } + mavenLocal() + } + resolutionStrategy { + eachPlugin { + when { + requested.id.id == "kotlinx-serialization" -> useModule("org.jetbrains.kotlin:kotlin-serialization:${requested.version}") + requested.id.id == "org.springframework.boot" -> useModule("org.springframework.boot:spring-boot-gradle-plugin:${requested.version}") + requested.id.id == "kvision" -> useModule("pl.treksoft:kvision-gradle-plugin:${requested.version}") + } + } + } +} +rootProject.name = "${ARTIFACT_ID}" \ No newline at end of file diff --git a/src/main/resources/images/email-black-18dp.svg b/src/main/resources/images/email-black-18dp.svg new file mode 100644 index 0000000..f2b51cb --- /dev/null +++ b/src/main/resources/images/email-black-18dp.svg @@ -0,0 +1 @@ + \ No newline at end of file